UNION
MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。多个 SELECT 语句会删除重复的数据。 (简单点就是对多个集合取并集)
语法规则
SELECT语句1
UNION [ALL | DISTINCT]
SELECT语句2
...(可以继续UNION,没限制select的语句个数)
可以自定义UNION后是否删除重复数据。
- DISTINCT: (可选)删除结果集中重复的数据,是UNION的默认情况(不加UNION条件)
- ALL:( 可选)返回所有结果集,包含重复数据。
测试样例
SELECT sno FROM sc WHERE cno='C001';
SELECT sno FROM sc WHERE cno='C003';
SELECT sno FROM sc WHERE cno='C001'
UNION
SELECT sno FROM sc WHERE cno='C003';
SELECT sno FROM sc WHERE cno='C001'
UNION ALL
SELECT sno FROM sc WHERE cno='C003';
[NOT] EXISTS
带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true”或者逻辑假值“false”。 将主查询的数据,放到子查询中做条件验证,根据验证结果(TRUE 或 FALSE)来决定主查询的数据结果是否得以保留。如果是EXIST,验证结果为true保留。如果是NOT EXISTS,验证结果是false保留。(这句话理解了就明白[NOT] EXISTS的执行原理了)
这个执行原理和非相关子查询(后面说)是一样的,先执行外查询结果,在放到子查询中验证。
语法规则: EXISTS一般放在查询语句的WHERE后面。 举个例子吧 这个语句的作用就是查询stu表中和张三同一个专业(mno)的学生的学生信息。 理一下执行顺序:先进行外部查询SELECT sno 学号, sname 姓名 FROM stu ,对于查询的每一条结果都放大EXISTS后面的子查询去验证,如果满足stu.mno=tt.mno AND tt.sname='张三' (和张三同一个专业),子查询返回true,显示查询结果。如果不满足子查询的条件返回false,不显示查询结果。
NOT EXISTS和这个差不多,就不解释了。
SELECT
sno 学号,
sname 姓名
FROM stu WHERE EXISTS(
SELECT * FROM stu tt WHERE stu.mno=tt.mno AND tt.sname='张三')
AND sname<>'张三';
这是NOT EXISTS语句的使用样例: 查询没有选修C语言的学生的学生信息。
SELECT
sno 学号,
sname 姓名
FROM stu
WHERE NOT EXISTS(
SELECT * FROM sc WHERE sc.cno=(SELECT cno FROM cou WHERE cname='C语言')
AND sc.sno=stu.sno);
WITH ROLLUP
WITH ROLLUP必须跟在GROUP BY后面,放在开头,突出强调!!!
当需要对数据库数据进行分类统计的时候,往往会用上groupby进行分组。而在groupby后面还可以加入WITH CUBE和WITH ROLLUP等关键字对数据进行汇总。
mysql只支持with rollup。
举个例子: 求出每个学生的总分并进行汇总。
SELECT
sno 学号,
IFNULL(SUM(grade),0) 总分
FROM sc GROUP BY sno WITH ROLLUP;
结果: 补充一个做题时遇到的问题: WITH ROLLUP,此函数是对聚合函数进行再次聚合,WITH ROLLUP是根据 GROUP BY后的第一个字段,进行分组聚合的。 所以下面这个sql代码呈现的效果不是我想要的。 怎么办呢?暂时解决的办法就是把课程名和成绩单独提出来,然后通过连接实现。
SELECT
IFNULL( t2.课程号, '张三' ) 课程号,
IFNULL( t2.课程号, '选修课程的' ) 课程名,
IFNULL( t1.成绩, '总学分和平均学分为' ) 成绩,
t2.总学分 总学分,
t2.平均学分 平均学分
FROM
(
SELECT
cou.cno 课程号,
cou.cname 课程名,
sc.grade 成绩
FROM
sc,
cou
WHERE
EXISTS ( SELECT * FROM stu WHERE stu.sname = '张三' AND sc.sno = stu.sno AND sc.cno = cou.cno )
AND sc.grade > 60
GROUP BY
cou.cno
) t1
RIGHT JOIN (
SELECT
cou.cno 课程号,
SUM( cou.credit ) 总学分,
AVG( cou.credit ) 平均学分
FROM
sc,
cou
WHERE
EXISTS ( SELECT * FROM stu WHERE stu.sname = '张三' AND sc.sno = stu.sno AND sc.cno = cou.cno )
AND sc.grade > 60
GROUP BY
cou.cno WITH ROLLUP
) t2 ON t1.课程号 = t2.课程号;
IFNULL
IFNULL() 函数用于判断第一个表达式是否为 NULL,如果为 NULL 则返回第二个参数的值,如果不为 NULL 则返回第一个参数的值。
IFNULL(第一个表达式, 第一个表达式为空的时候返回的第二个参数的值)
使用可以看上面那个张三选修课程的总学分和平均学分。
NOT EXISTS表示关系除法
sql中关系除法的表示
not exists(
not exists( )
)
看个例题来理解一下吧 题目是这样的 这是代码
SELECT sname FROM stu WHERE sno=(
SELECT sno FROM stu WHERE NOT EXISTS(
SELECT * FROM (SELECT * FROM cou WHERE teacher='张老师') AS tt
WHERE NOT EXISTS
(
SELECT * FROM sc WHERE sc.cno=tt.cno
AND sc.sno=stu.sno
)
)
);
我们来简单理一下思路一下:我们要求B集合,可以求(非非B)集合,第一个NOT EXISTS就是第一个非,第二个NOT EXISTS就是第二个非。 选修张老师所有课程的学生,第一个非就是(没有)选修张老师所有课程的学生,第二个非就是存在张老师课没有选的学生。最后就是(没有)存在张老师所有课程(没选)的学生。
上面那个代码可以这样理解 1)相当于两个for循环,外层循环就是遍历所有学生记录,里层循环就是对每一条学生数据遍历张老师所有的课。 2)将每一条学生数据和张老师的所有课比对,如果发现not exists即存在张老师的课没选的情况,那这条学生记录被里层循环返回给外层循环的就是true,那么外层循环返回的就是false,这样这条学生记录就不显示。 (其实这么对执行的理解应该不对,但是暂时没找到更好的说法了)。
相关子查询和非相关子查询
想关子查询就是从外层查询表抽一条数据,然后放到内层查询去比对。 非相关子查询的执行不依赖与外部的查询。执行顺序:非相关子查询是先进行内层查询,其结果不被显示,而是传递给外部查询,作为外部查询的条件使用。再进行外层查询,外层每抽取一条记录都直接查看内层查询返回结果,不用多次执行内层查询。
简而言之就是想关子查询相当于for循环的签到,非相关子查询的内层循环只执行一次。
|