目录
MySQL常见的建表约束(重要)
约束名称 | 描述 |
---|---|
NOT NULL | 非空约束,字段不允许为null |
UNIQUE | 唯一约束,该字段的取值不允许重复, |
PRIMARY KEY | 主键约束(主关键字),自带非空、唯一、索引 |
FOREIGN KEY | 外键约束(外关键字,有外键关联的表不能直接删除) |
DEFAULT | 默认值(缺省值) |
Mysql数据查询语言(最重要)
重点,该语言用来查询记录,不会修改数据库和表结构。
初始化测试数据
创建测试用的表:
drop TABLE if EXISTS student;
CREATE TABLE student (
id INT(10) PRIMARY key,
name VARCHAR (10),
age INT (10) NOT NULL,
gander varchar(2)
);
drop TABLE if EXISTS course;
CREATE TABLE course (
id INT (10) PRIMARY key,
name VARCHAR (10) ,
t_id INT (10)
) ;
drop TABLE if EXISTS teacher;
CREATE TABLE teacher(
id INT (10) PRIMARY key,
name VARCHAR (10)
);
drop TABLE if EXISTS scores;
CREATE TABLE scores(
s_id INT ,
score INT (10),
c_id INT (10) ,
PRIMARY key(s_id,c_id)
) ;
往表中插入数据:
insert into student (id,name,age,gander)VALUES(1,'白杰',19,'男');
insert into student (id,name,age,gander)VALUES(2,'连宇栋',19,'男');
insert into student (id,name,age,gander)VALUES(3,'邸志伟',24,'男');
insert into student (id,name,age,gander)VALUES(4,'李兴',11,'男');
insert into student (id,name,age,gander)VALUES(5,'张琪',18,'男');
insert into student (id,name,age,gander)VALUES(6,'武三水',18,'女');
insert into student (id,name,age,gander)VALUES(7,'张志伟',16,'男');
insert into student (id,name,age,gander)VALUES(8,'康永亮',23,'男');
insert into student (id,name,age,gander)VALUES(9,'杨涛瑞',22,'女');
insert into student (id,name,age,gander)VALUES(10,'王杰',21,'男');
insert into course (id,name,t_id)VALUES(1,'数学',1);
insert into course (id,name,t_id)VALUES(2,'语文',2);
insert into course (id,name,t_id)VALUES(3,'c++',3);
insert into course (id,name,t_id)VALUES(4,'java',4);
insert into course (id,name)VALUES(5,'php');
insert into teacher (id,name)VALUES(1,'张楠');
insert into teacher (id,name)VALUES(2,'老孙');
insert into teacher (id,name)VALUES(3,'薇薇姐');
insert into teacher (id,name)VALUES(4,'磊磊哥');
insert into teacher (id,name)VALUES(5,'大微姐');
insert into scores (s_id,score,c_id)VALUES(1,80,1);
insert into scores (s_id,score,c_id)VALUES(1,56,2);
insert into scores (s_id,score,c_id)VALUES(1,95,3);
insert into scores (s_id,score,c_id)VALUES(1,30,4);
insert into scores (s_id,score,c_id)VALUES(1,76,5);
insert into scores (s_id,score,c_id)VALUES(2,35,1);
insert into scores (s_id,score,c_id)VALUES(2,86,2);
insert into scores (s_id,score,c_id)VALUES(2,45,3);
insert into scores (s_id,score,c_id)VALUES(2,94,4);
insert into scores (s_id,score,c_id)VALUES(2,79,5);
insert into scores (s_id,score,c_id)VALUES(3,65,2);
insert into scores (s_id,score,c_id)VALUES(3,85,3);
insert into scores (s_id,score,c_id)VALUES(3,37,4);
insert into scores (s_id,score,c_id)VALUES(3,79,5);
insert into scores (s_id,score,c_id)VALUES(4,66,1);
insert into scores (s_id,score,c_id)VALUES(4,39,2);
insert into scores (s_id,score,c_id)VALUES(4,85,3);
insert into scores (s_id,score,c_id)VALUES(5,66,2);
insert into scores (s_id,score,c_id)VALUES(5,89,3);
insert into scores (s_id,score,c_id)VALUES(5,74,4);
insert into scores (s_id,score,c_id)VALUES(6,80,1);
insert into scores (s_id,score,c_id)VALUES(6,56,2);
insert into scores (s_id,score,c_id)VALUES(6,95,3);
insert into scores (s_id,score,c_id)VALUES(6,30,4);
insert into scores (s_id,score,c_id)VALUES(6,76,5);
insert into scores (s_id,score,c_id)VALUES(7,35,1);
insert into scores (s_id,score,c_id)VALUES(7,86,2);
insert into scores (s_id,score,c_id)VALUES(7,45,3);
insert into scores (s_id,score,c_id)VALUES(7,94,4);
insert into scores (s_id,score,c_id)VALUES(7,79,5);
insert into scores (s_id,score,c_id)VALUES(8,65,2);
insert into scores (s_id,score,c_id)VALUES(8,85,3);
insert into scores (s_id,score,c_id)VALUES(8,37,4);
insert into scores (s_id,score,c_id)VALUES(8,79,5);
insert into scores (s_id,score,c_id)VALUES(9,66,1);
insert into scores (s_id,score,c_id)VALUES(9,39,2);
insert into scores (s_id,score,c_id)VALUES(9,85,3);
insert into scores (s_id,score,c_id)VALUES(9,79,5);
insert into scores (s_id,score,c_id)VALUES(10,66,2);
insert into scores (s_id,score,c_id)VALUES(10,89,3);
insert into scores (s_id,score,c_id)VALUES(10,74,4);
insert into scores (s_id,score,c_id)VALUES(10,79,5);
一.单表查询
1.基本查询(后缀都是统一为from 表名)
(1)查询所有列:select * from 表名;
其中*表示查询所有列,而不是所有行的意思。
(2)查询指定列:select 列1,列2,列n from 表名;
(3)完全重复的记录只显示一次:在查询的列之前添加distinct
(4)列运算
a.【数量类型的列】可以做加、减、乘、除:SELECT sal*5 from 表名;
说明:
1.遇到null加任何值都等于null的情况,需要用到ifnull()函数。
2.将字符串做加减乘除运算,会把字符串当作0。
b.字符串累类型可以做连续运算(需要用到concat()函数):select concat(列名1,列名2) from 表名;其中列名的类型要为字符串。
c. 给列名起别名:select 列名1 (as) 别名1,列名2 (as) 别名2 from 表名;(帮列取和帮表取别名是非常常用的)
(5)条件控制
a.条件查询。在后面添加where指定条件:`select * from 表名 where 列名=指定值;` = < > in (in相当于 or的一个集合)
b.【模糊查询】:当你想查询所有姓张的记录。用到【关键字like】。
select * from 表名 where 列名 like '张_';
(_代表匹配任意一个字符,%代表匹配0~n个任意字符)。
2.排序(所谓升序和降序都是从上往下排列)
-
1.升序:
select * form 表名 order by 列名 ASC ;
-
2.降序:
select * from 表名 order by 列名 DESC;
-
3.使用多列作为排序条件: 当第一列排序条件相同时,根据第二列排序条件排序(当第二列依旧相同时可视情况根据第三例条件排序)。eg:
select * from 表名 order by 列名1 ASC, 列名2 DESC;
意思是当列名1的值相同时按照列名2的值降序排。
3.聚合函数
-
1.count:
select count(列名) from 表名;
,记录行数。 最常用; -
2.max:
select max(列名) from 表名;
,列中最大值。select max(age) from student;
-
3.min:
select min(列名) from 表名;
,列中最小值。 -
4.sum:
select sum(列名) from 表名;
,求列的总值,null 和字符串默认为0。 -
5.avg:
select avg(列名) from 表名;
,一列的平均值。
4.分组查询
分组查询的信息都是组的信息,不能查到个人的信息,其中查询组的信息是通过聚合函数得到的。
语法:select 分组列名,聚合函数1,聚合函数2 from 表名 group by 该分组列名;
其中分组列名需要的条件是该列名中有重复的信息。
查询的结果只能为:作为分组条件的列和聚合函数;查出的信息都是组的信息。
SELECT gander,AVG(age) from student GROUP BY gander;
反例: 这样只会把第一个数据拿出来分组:
分组查询前,还可以通过关键字where先把满足条件的人分出来,再分组。语法为:select 分组列,聚合函数 from 表名 where 条件 group by 分组列;
分组查询后,也可以通过关键字having把组信息中满足条件的组再细分出来(对组再进行条件细分只能使用having)。语法为:select 分组列,聚合函数 from 表名 where 条件 group by 分组列 having 聚合函数或列名(条件);
select gander,avg(age) avg_age,sum(age) sum_age from student GROUP BY gander HAVING gander = '男'
5.LIMIT子句(mysql中独有的语法)
LIMIT用来限定查询结果的起始行,以及总行数。 可以用来分页查询
例如:select * from 表名 limit 4,3;
表示起始行为第5行,一共查询3行记录。
--如果一个参数 说明从开始查找三条记录
SELECT id,name,age,gander FROM student limit 3
--如果两个参数 说明从第四行开始向后查三条记录(包括第四行,行数的计数是从0开始到)
SELECT id,name,age,gander FROM student limit 3,3
SELECT * FROM tbl_book LIMIT 2,3
二.多表查询(最重要的)
以后在企业中这种多表的查询是需要程序员自己手写的 ;
笛卡尔积:简单来说就是两个集合相乘的结果,集合A和集合B中任意两个元素结合在一起
1.内,外连接
内连接 :
内连接查询操作只列出与连接条件匹配的数据行,使用INNER JOIN或者直接使用JOIN 进行连接。
内连接可以没有连接条件,没有条件之后的查询结果,会保留所有结果(笛卡尔集),与后面分享的交叉连接差不多。
在连接条件中使用等于号(=)运算符比较被连接列的列值,其查询结果中列出被连接表中的所有列,包括其中的重复列。
查询结果,注意列数是 4 列,两张表的字段直接拼接在一起,重复的字段在后面添加数字序列以做区分;
通俗讲就是根据条件,找到表 A 和 表 B 的数据的交集;
例子:
普通的多表查,课内连接接通相同
SELECT * from teacher t , course c where t.id = c.t_id
(这样会先生成笛卡尔积,效率可能略低)
SELECT * from teacher t JOIN course c on t.id = c.t_id
SELECT * from teacher t inner JOIN course c on t.id = c.t_id
结果:只有满足条件的会显示,5号老师没课程,5号课程没老师都不会显示 【即所有有null的数据不显示,不满足条件的也不显示,重复的数据会被覆盖只留一个】
1 王宝强 1 数学 1
2 贾宝玉 2 语文 2
3 温迪 3 c++ 3
4 路人甲 4 java 4
2、外连接(常用)
外连接不只列出与连接条件相匹配的行,而且还加上左表(左外连接时)或右表(右外连接时)或两个表(全外连接时)中所有符合搜索条件的数据行。
2.左连接(左外连接)
根据条件,用右表(B)匹配左表(A),能匹配,正确保留,不能匹配其他表的字段都置空 Null。
也就是,根据条件找到表 A 和 表 B 的数据的交集,再加上左表的数据集, Venn 图表示就是:
红色部分代表查询结果;
例子:
SELECT * from teacher t LEFT JOIN course c on t.id = c.t_id
结果:只有满足条件的会显示,5号老师没课程,依然显示,5号课程没老师都不会显示,
左边表的所有数据都显示
1 王宝强 1 数学 1
2 贾宝玉 2 语文 2
3 温迪 3 c++ 3
4 路人甲 4 java 4
5 路人乙
3.右连接(右外连接)
根据条件,用左表(A)匹配右表(B),能匹配,正确保留,不能匹配其他表的字段都置空 Null。
也就是,根据条件找到表 A 和 表 B 的数据的交集,再加上右表的数据集, Venn 图表示就是:
例子:
SELECT * from teacher t right JOIN course c on t.id = c.t_id
结果:只有满足条件的会显示,5号老师没课程不显示,5号课程没老师都,依然显示,
右边表的所有数据都显示
1 王宝强 1 数学 1
2 贾宝玉 2 语文 2
3 温迪 3 c++ 3
4 路人甲 4 java 4
5 php
4.全连接,mysql不支持,oracle支持
目前我的 MySQL 不支持此种方式,可以用其他方式替代解决,在此不展开。
理论上是根据条件找到表 A 和 表 B 的数据的交集,再加上左右表的数据集:
但是我们可以把左联合右联的结果联合起来,就可以达到取全集的结果;
select * from teacher t right join course c on t_id = c.t_id
union
select * from teacher t left join course c on t.id + c.t_id;
问题:求两张表的交集 ---内连接
求两张的并集---全连接,但是MySQL中没有全连接,所以可以使用左右连接的结果联合一下(union)
union 会把重复的内容给覆盖,只显示一个;
union all 把联合的表达数据全部合在一起,不管是否重复;
三.子查询
1.where 型子查询
【将查询结果当条件】
例子:查询有一门学科分数大于八十分的学生信息
SELECT * from student where id in
(select DISTINCT s_id from scores where score > 90);
where 型子查询,如果是 where 列 =(内层 sql) 则内层 sql 返回的必须是单行单列,单个值。
where 型子查询,如果是 where 列 in(内层 sql) 则内层 sql 返回的必须是单列,可以多行。
2.from 型子查询
在学习 from 子查询之前,需要理解一个概念:【查询结果集在结构上可以当成表看】,那就可以当成临时表对他进行再次查询:
取排名数学成绩前五名的学生,正序排列。
select * from (SELECT s.id,s.name,e.score,c.`name` cname from student s LEFT JOIN scores e
on s.id = e.s_id left JOIN course c on e.c_id = c.id
where c.`name` = '数学' order by e.score desc limit 5 ) t ORDER BY t.score
on后面接的是连接条件,
where后面接的是筛选条件,
group by 后面接的是分组条件;
四.sql练习题(含答案)
1、查询‘01’号学生的姓名和各科成绩,要求成绩要与课程对应。
select
s.`name` "学生名字",
e.name "课程名称",
c.score "成绩"
from student s
LEFT JOIN scores c
on s.id = c.s_id
LEFT JOIN course e
on e.id = c.c_id 这个第二次左联不能直接使用and把两个on的条件直接写一起!!!
where s.id = 11
2、查询各个学科的平均成绩,最高成绩。
SELECT c.`name`,AVG(score),MAX(score) from course c
left JOIN scores s
on c.t_id = s.c_id
GROUP BY c.`name`
3、查询每个同学的最高成绩及科目名称。
-- 答案
SELECT t.`name`,MAX(c.score),cou.`name` as '学科'
FROM student t
LEFT JOIN scores c
on t.id = c.s_id
LEFT JOIN course cou
on c.c_id = cou.id
GROUP BY `name`
-- GROUP BY 如果查询的字段的结果不止一个(比如一个人会有多门课程的成绩),那么分组查询(使用这个字段分组)的结果只会显示前面的一个,那么我就可以利用分组的这个特性查询出一个人的成绩最值,以此类推;
-- 比如下面这个案列 我们是通过name来进行分组,一个人的成绩是有有多门的,但是分组后只能显示name(查询字段)的【第一个成绩】,如果不分组那么就只能查询到一个人的成绩 下面的SQL是测试这个用的
SELECT t.`name`,c.score
FROM student t
LEFT JOIN scores c
on t.id = c.s_id
GROUP BY `name`
4、查询所有姓张的同学的各科成绩。
SELECT stu.`name`,s.score,c.`name` AS '课程'
FROM student stu
LEFT JOIN scores s
on stu.id = s.s_id
LEFT JOIN course c
on s.c_id = c.id
WHERE stu.name LIKE '张%'
-- 模糊查询的条件一定要加在where后面,并且要指定那一列进行模糊查询,否则语法错误
5、查询课程编号为01且课程成绩在60分以上的学生的学号和姓名。
select s.id,s.name from student s where
s.id in (
select c.s_id from scores c
where c.c_id = '1' and c.score > 60
)
6、查询课程名称为”java”,且分数低于60的学生姓名和分数。
select s.`name`,m.score from student s left join
(select c.s_id,c.score
from scores c left JOIN course t
on c.c_id = t.id
where t.name = 'java' and c.score < 60) m
on m.s_id = s.id
where m.s_id is not null