zoukankan      html  css  js  c++  java
  • SQL基础-子查询&EXISTS&UNION

    一、子查询

    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比较

    existsin 最大的区别在于 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 ALLUNION:
        相同点:都是用来合并多个结果集;
    
        不同点: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。
    
    以上主要针对的是单表,而多表联合查询来说,考虑的地方就比较多了,比如连接方式,查询表数据量分布、索引等,再结合单表的策略选择合适的关键字;
  • 相关阅读:
    GitLab → 搭建中常遇的问题与日常维护
    GitLab → 搭建私有的版本控制的托管服务平台
    神奇的 SQL 之 ON 和 WHERE → 扑朔迷离,好多细节!
    神奇的 SQL 之 ICP → 索引条件下推
    神奇的 SQL 之 WHERE 条件的提取与应用
    记一次线上问题 → 事务去哪了
    神奇的 SQL 之 联表细节 → MySQL JOIN 的执行过程(二)
    神奇的 SQL 之 联表细节 → MySQL JOIN 的执行过程(一)
    python之pip安装mysql-python失败
    python之celery使用详解(二)
  • 原文地址:https://www.cnblogs.com/weiyiming007/p/11433785.html
Copyright © 2011-2022 走看看