MySQL基础
MySQL数据管理
外键约束
- 什么是外键?
外键是相对于主键说的,是建立表之间的联系的必须的前提,比如有两张表,student(学生)表和grade(年级)表,student 中 id 是主键,而 gradeid 是依赖于 student 中的 id ,那么 grade 中的 id 就是 student 的外键;我们可以通过外键使两张表进行关联。 - 外键的作用是什么?
使两张表形成关联,外键只能引用外表中的列的值,可以使得两张表关联,保证数据的一致性和实现一些级联操作。
总结:
1)为了一张表记录的数据不要太过冗余;
2)保持数据的一致性、完整性。
- CREATE TABLE 时:
-- 创建grade表
CREATE TABLE `grade`(
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',
`gradename` VARCHAR(50) NOT NULL COMMENT '年级名称',
PRIMARY KEY (`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-- 学生表的 gradeid 字段,去引用年级表的 gradeid
-- 定义外键key
-- 给这个外键添加约束 (执行引用) references 引用
CREATE TABLE IF NOT EXISTS `student` (
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20)NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`gradeid` INT(10) NOT NULL COMMENT '学生的年级',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`),
KEY `FK_gradeid` (`gradeid`),
CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
可视化查看表可以看到:
- ALTER TABLE 时:
-- 当我们的student表已经存在时,添加外键约束
CREATE TABLE IF NOT EXISTS `student` (
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20)NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`gradeid` INT(10) NOT NULL COMMENT '学生的年级',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-- ALTER TABLE 表
-- ADD CONSTRAINT 约束名 FOREIGN KEY(作为外键的列) REFERENCES 哪个表(哪个字段)
ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`gradeid`);
和上面结果一样。
- 注意:
加入外键约束后,没删除student表前,是无法删除grade表的;
一般也不推荐使用外键约束,阿里巴巴的Java规范下是:强制不得使用外键,一切外键在应用层解决,原因就是在DELETE或者UPDATE时都要考虑外键约束,导致开发变得痛苦很多!
DML语言
DML:数据操纵语言(Data Manipulation Language),它可以实现对数据库的基本操作。
开始我们创建一个school数据库,里面包含了以下的表,接下来的操作都是在此数据库里进行的
- 添加(INSERT)
语法:INSERT INTO 表名([字段名1,字段2,字段3,...]) VALUES ('值1'),('值2'),('值3',....)
-- 给上面的student表插入数据
INSERT INTO `student`(`name`) VALUES ('张三')
INSERT INTO `studnet` VALUES('李四') -- 如果不写表的字段,他就会一一匹配,这条语句就会报错!
-- 插入多个字段
INSERT INTO `student`(`name`,`pwd`,`sex`) VALUES ('张三','123456','男')
INSERT INTO `student`(`name`,`pwd`,`sex`) VALUES ('李四','123456','男'),('王五','aaaaaa','男')
- 注意:
1)字段和字段之间使用英文逗号隔开;
2)字段是可以省略的,但是后面的值必须要要一一对应,不能缺少数据;
3)可以同时插入多条数据,VALUES 后面的值,需要使用逗号隔开。
- 修改(UPDATE)
语法:UPDATE 表名 SET colnum_name = value,[colnum_name = value,....] WHERE [条 件]
-- 修改student表name字段
UPDATE `student` SET `name`='小明' WHERE id = 1;
-- 不指定条件的情况下,会改动所有表
UPDATE `student` SET `name`='小红';
-- 修改多个属性,逗号隔开
UPDATE `student` SET `name`='小强',`email`='123456@qq.com' WHERE id = 1;
- 注意:
1)WHERE 条件子句 :id 等于某个值,或大于某个值,表示在某个区间内修改;
2)colnum_name 是数据库的列,尽量带上`` ;
3)条件,筛选的条件,如果没有指定,则会修改所有的列;
4)value,是一个具体的值,也可以是一个变量;
5)多个设置的属性之间,使用英文逗号隔开。
通过多个条件定位数据
UPDATE `student` SET `name`='小强' WHERE `name`='张三' AND sex='男'
- 删除(DELETE)
语法:DELETE FROM 表名 [WHERE 条件]
-- 删除数据 (这样写,会全部删除)
DELETE FROM `student`;
-- 删除指定数据
DELETE FROM `student` WHERE id = 1;
完全清空一个数据库表(TRUNCATE)
--清空 student 表
TRUNCATE `student`;
DELETE 和 TRUNCATE:
相同点:都能删除数据,都不会删除表结构
不同点: DELETE ,不会影响自增;TRUNCATE ,重新设置自增列,计数器会归零 。
DQL语言
DQL:数据查询语言(Data Query Language,所有的查询操作都用它,数据库中最核心的语言,最重要的语句,使用频率最高的语句。
- 指定查询字段
-- 查询全部的学生 SELECT 字段 FROM 表
SELECT * FROM student
-- 查询指定字段
SELECT `StudentNo`,`StudentName` FROM student
-- 给查询结果赋值一个新的名字 AS 可以给字段起别名,也可以给表起别名
SELECT `StudentNo` AS 学号,`StudentName` AS 学生姓名 FROM student AS s
-- 函数 Concat(a,b),给查询结果拼接一个字符串
SELECT CONCAT('姓名:',StudentName) AS 新名字 FROM student
有的时候,列名字不是那么的见名知意,所以我们赋值一个新的名字,语法:字段名 AS 别名 表名 AS 别名
- 去重 (DISTINCT)
去除SELECT 查询出来的结果中重复的数据,重复的数据只显示一条
SELECT DISTINCT `StudentNo` FROM result
- 数据库的列(表达式)
-- 查询系统版本 (函数)
SELECT VERSION()
-- 用来计算 (表达式)
SELECT 100*3-1 AS 计算的结果为
-- 查询自增的步长 (变量)
SELECT @@auto_increment_increment
-- 给student表的考试成绩都 + 1分
SELECT `StudentNo`,`StudentResult`+1 AS '提分后' FROM result
- WHERE条件子句
用来检索数据中 符合条件 的值
MySQL官网的函数和运算符说明:点击这里
简单说几个:
符号 | 描述 | 语法 |
---|---|---|
<> 或 != | 不等于 | id <> 3、id != 3 |
BETWEEN … and … | 在某个范围内 | |
AND、&& | 逻辑与 | a and b 、 a&&b |
OR | 逻辑或 | a or b |
Not ! | 逻辑非 | not a !a |
IS NULL | 如果操作符为 NUll, 结果为真 | a is null |
IS NOT NULL | 如果操作符不为 null,结果为真 | a is not null |
BETWEEN | 若a 在 b 和c 之间,则结果为真 | a between b and c |
LIKE | SQL 匹配,如果a匹配b,则结果为真 | a like b |
In | a在a1,或者a2…. 其中的某一个值中,结果为真 | a in (a1,a2,a3….) |
-- 查询考试成绩在 95~100 分之间
SELECT studentNo,`StudentResult` FROM result
WHERE StudentResult>=95 AND StudentResult<=100
-- 模糊查询(区间)
SELECT studentNo,`StudentResult` FROM result
WHERE StudentResult BETWEEN 95 AND 100
-- 查询学号不为1000的学生成绩
SELECT studentNo,`StudentResult` FROM result
WHERE studentNo!=1000;
SELECT studentNo,`StudentResult` FROM result
WHERE NOT studentNo = 1000
模糊查询:
-- 查询姓张的同学
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE StudentName LIKE '张%' -- %(代表0到任意个字符)
-- 查询姓刘的同学,而且名字后面只有一个字的
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE StudentName LIKE '刘_' -- _(代表一个字符)
-- 查询姓刘的同学,名字后面只有两个字的
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE StudentName LIKE '刘__'
-- 查询名字中间有坤字的同学 %坤%
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE StudentName LIKE '%坤%'
-- 查询 1001,1002,1003号学生
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE StudentNo IN (1001,1002,1003);
-- 查询地址为北京的学生
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE `Address` IN ('北京');
-- 查询地址为空的学生 null ''
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE address='' OR address IS NULL
-- 查询有出生日期的同学,不为空
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE `BornDate` IS NOT NULL
-- 查询没有登记出生日期的同学,为空
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE `BornDate` IS NULL
- 注意:
WHERE IN()查询时,IN()里面是具体的值,如果地址是北京市海淀区,当你输入WHERE Address IN ('北京')
,结果是查询不到的,只能采用WHERE Address LIKE '%北京%'
。
- 联表查询(JOIN)
LEFT JOIN、RIGHT JOIN、INNER JOIN、OUTER JOIN 相关的 7 种用法
- 思路:
1)分析需求,分析查询的字段来自哪些表?并进行连接查询;
2)确定使用上图的哪种连接查询?
3)确定交叉点(这两个表中哪个数据是相同的;
4)判断的条件
-- INNER JOIN
SELECT s.studentNO,studentName,SubjectNo,StudentResult
FROM student AS s
INNER JOIN result AS r
ON s.studentNO = r.studentNO
-- Right JOIN
SELECT s.studentNO,studentName,SubjectNo,StudentResult
FROM student s
RIGHT JOIN result r
ON s.studentNO = r.studentNO
-- Left JOIN
SELECT s.studentNO,studentName,SubjectNo,StudentResult
FROM student s
LEFT JOIN result r
ON s.studentNO = r.studentNO
- 注意:
JOIN | 描述 |
---|---|
INNER JOIN | 如果表中有至少一个匹配,则返回行 |
LEFT JOIN | 即使右表中没有匹配,也从左表返回所有的行 |
RIGHT JOIN | 即使左表中没有匹配,也从右表返回所有的行 |
- 总结:
联表查询思路:
1)首先确定要查询哪些数据:SELECT ...
2)从哪几个表中查FROM 表 XXX JOIN 连接的表 on 交叉条件
3)假设存在一种多张表查询,先查询两张表,然后再慢慢增加。
- 自连接
自己的表和自己的表连接,将一张表拆为两张一样的表即可
假设一张表:
categoryid | pid | categoryName |
---|---|---|
2 | 1 | 水果 |
3 | 1 | 蔬菜 |
4 | 3 | 土豆 |
5 | 1 | 肉类 |
6 | 3 | 青菜 |
7 | 5 | 猪肉 |
8 | 2 | 西瓜 |
拆分这张表:
表1:
categoryid | categoryName |
---|---|
2 | 水果 |
3 | 蔬菜 |
5 | 肉类 |
表二:
pid | categoryid | categoryName |
---|---|---|
3 | 4 | 土豆 |
2 | 8 | 西瓜 |
3 | 6 | 青菜 |
5 | 7 | 猪肉 |
操作:查询父类对应的子类关系
父类 | 子类 |
---|---|
水果 | 西瓜 |
蔬菜 | 土豆、青菜 |
肉类 | 猪肉 |
-- 通过别名将一张表看作两个一摸一样的表
SELECT a.`categoryName` AS '父栏目',b.`categoryName` AS '子栏目'
FROM `category` AS a,`category` AS b
WHERE a.`categoryid` = b.`pid`
- 排序和分页
- 排序(ORDER BY)
-- 升序 ASC , 降序DESC
ORDER BY StudentResult ASC、DESC
- 分页(LIMIT)
缓解数据库压力,给人的体验更好
语法:LIMIT (查询起始下标,pageSize)
第一页 LIMIT 0,5 (1-1)*5
第二页 LIMIT 5,5 (2-1)*5
第三页 LIMIT 10,5 (3-1)*5
第N页 LIMIT 0,5 (n-1)* pageSize,pageSize
pageSize:页面大小
(n-1)* pageSize:起始值
n :当前页
数据总数/页面大小 = 总页数
- 子查询
在where语句中嵌套一个子查询语句,查询高数考试学生的成绩、学号,成绩降序排序
-- 方式一: 使用连接查询
SELECT `StudentNo`,r.`SubjectNo`,`StudentResult`
FROM `result` r
INNER JOIN `subject` sub
ON r.SubjectNo = sub.SubjectNo
WHERE SubjectName = '高数'
ORDER BY StudentResult DESC
-- 方式二: 使用子查询(由里及外) -- 查询所有数据库结构-1 的学生学号
SELECT `StudentNo`,`SubjectNo`,`StudentResult`
FROM `result` WHERE SubjectNo = (
SELECT SubjectNo FROM `subject`
WHERE SubjectName = '高数'
) ORDER BY StudentResult DESC
- 过滤分组
-- 通过什么字段来分组
GROUP BY xxx
-- 过滤分组后的信息,需要满足的条件,次要条件
HAVING xxx
//下篇再见…谢谢