一、子查询
1、使用子查询作为计算字段
子查询:嵌套在其他查询中的查询现在有两个表,student表和teacher表创建teacher表,并插入数据:CREATE TABLE `teacher` ( `teacher_id` varchar(255) DEFAULT NULL COMMENT '老师编号', `teacher_name` varchar(255) DEFAULT NULL COMMENT '老师姓名', `gender` varchar(255) DEFAULT NULL COMMENT '性别') ENGINE=MyISAM DEFAULT CHARSET=gbk COMMENT='老师';INSERT INTO `teacher` VALUES ('T0001','高齐妍','男'),('T0002','李红','女'),('T0003','李一萱',NULL),('T0004','刘金霞','男'),('T0005','刘思哲','男'),('T0006','刘兆祥','男'),('T0007','刘哲宇','男'),('T0008','梅艺涵','女'),('T0009','梅姿君','女'),('T0010','牛雨','女'),('T0011','牛光滢','女'),('T0012','黄雅','女'),('T0013','任筱','女'),('T0014','吴静婷','男'),('T0015','习芸颍','女'),('T0016','叶惠燕','女'),('T0017','周纯','男'),('T0018','周圣杰','男'),('T0019','方焓','女'),('T0020','方杰萍','女');比如: 如何同时查询出学生编号、学生姓名、老师编号、老师姓名? SELECT student_id, student_name, teacher_id, ( SELECT teacher_name FROM teacher -- 使用表名消除字段歧义 WHERE teacher.teacher_id = student.teacher_id ) FROM student; #可以为表指定别名 SELECT student_id, student_name, teacher_id, ( SELECT teacher_name FROM teacher b WHERE b.teacher_id = a.teacher_id ) FROM student a;此时子查询不能返回多条记录;
2、使用子查询过滤数据(IN)
比如: 如何获取姓牛的老师教了哪些学生? SELECT student_id,student_name FROM student WHERE teacher_id IN ( SELECT teacher_id FROM teacher WHERE teacher_name like '牛%');in 后面是一个集合;
3、IN和EXISTS比较
exists 与 in 最大的区别在于 in引导的子句只能返回一个字段;exists强调的是是否返回结果集,不要求知道返回什么;exists 是用来判断是否存在的,当exists(查询)中的查询存在结果时则返回真否则返回假。not exists则相反。EXISTS只返回TRUE或FALSE,不会返回UNKNOWN。IN当遇到包含NULL的情况,那么就会返回UNKNOWN。exists做为where条件时,是先对where前的主查询询进行查询,然后用主查询的结果一个一个的代入exists的查询进行判断,如果为真则输出当前这一条主查询的结果,否则不输出。select * from A where id in(select id from B)in()适合B表比A表数据小的情况;exists()适合B表比A表数据大的情况;当A表数据与B表数据一样大时,in与exists效率差不多,可任选一个使用;
4、使用子查询过滤数据(EXISTS)
比如: 如何获取姓牛的老师教了哪些学生? SELECT student_id,student_name FROM student a -- 这里的select 1没有具体意义,写成select 2也可以; WHERE EXISTS ( SELECT 1 FROM teacher b WHERE a.teacher_id = b.teacher_id AND b.teacher_name like '牛%' );##NO EXISTS比如: 如何获取除姓牛的老师之外的其他老师教了哪些学生? SELECT student_id,student_name FROM student a WHERE NOT EXISTS ( SELECT 1 FROM teacher b WHERE a.teacher_id = b.teacher_id AND b.teacher_name like '牛%' );
二、UNION
1、UNION 和UNION ALL
##比如: 如何同时查询出年龄为10岁或一年级一班的所有学生? SELECT * FROM student WHERE age = 10 UNION ALL SELECT * FROM student WHERE class_id = 'G0101';比如: 如何同时查询出年龄为10岁或一年级一班的所有学生(去除重复)? SELECT * FROM student WHERE age = 10 UNION SELECT * FROM student WHERE class_id = 'G0101';UNION ALL 与 UNION: 相同点:都是用来合并多个结果集; 不同点:UNION ALL合并结果集后不去除重复记录; UNION合并结果集后去除重复记录;
2、合并2个以上的结果集
比如: 如何同时查询出年龄为10岁或一年级一班或性别为男的所有学生? SELECT * FROM student WHERE age = 10 UNION SELECT * FROM student WHERE class_id = 'G0101' UNION SELECT * FROM student WHERE gender = '男';
3、合并来源于不同的表的结果集
比如: 如何同时查询出所有的学生编号、学生姓名和老师编号、老师姓名? SELECT student_id,student_name FROM student UNION SELECT teacher_id,teacher_name FROM teacher;
4、不同结果集什么情况下可以合并
需要注意: 待合并的结果集的字段数量必须一致。错误写法(字段数量不一致): SELECT student_id,student_name,age FROM student UNION SELECT teacher_id,teacher_name FROM teacher;其他注意的几点: 合并后的结果集的title与第一个结果集保持一致。 待合并的结果集的字段顺序、字段类型的大类及字段值的含义尽量保持一致。如下,虽然不会报错,但是也应该尽量避免不一样的字段在同一列: SELECT student_id,student_name,age FROM student UNION SELECT teacher_id,teacher_name,gender FROM teacher;以上注意事项,UNION和UNION ALL都适用;
5、UNION ALL与UNION混用
比如: 如何同时查询出年龄为10岁或一年级一班(前面两个结果集需要去除重复)或性别为男(合并时不去除重复)的所有学生? SELECT * FROM student WHERE age = 10 UNION SELECT * FROM student WHERE class_id = 'G0101' UNION ALL SELECT * FROM student WHERE gender = '男';需要注意的几点: UNION ALL与UNION的执行优先级一致,谁在前谁先执行; 不可以使用括号改变执行优先级;不建议UNION ALL与UNION混用;
6、合并后的结果集排序
比如: 如何同时查询出年龄为10岁或一年级一班的所有学生(按姓名升序排序)? SELECT * FROM student WHERE age = 10 UNION ALL SELECT * FROM student WHERE class_id = 'G0101' ORDER BY student_name;会先执行UNION ALL,再执行ORDER BY
7、union all&or&in的使用
union all 也不一定就比 or及in 快,要结合实际情况分析到底使用哪种情况。对于索引列来最好使用union all,因复杂的查询【包含运算等】将使or、in放弃索引而全表扫描,除非你能确定or、in会使用索引;对于只有非索引字段来说你就老老实实的用or 或者in,因为 非索引字段本来要全表扫描而union all 只成倍增加表扫描的次数;对于既有索引字段【索引字段有效】又包含非索引字段来时,按理你也使用or 、in或者union all 都可以,但是我推荐使用or、in。以上主要针对的是单表,而多表联合查询来说,考虑的地方就比较多了,比如连接方式,查询表数据量分布、索引等,再结合单表的策略选择合适的关键字;