浅谈mysql双层not exists查询执行流程

 更新时间:2023年06月13日 11:14:20   作者:lanren312  
本文主要介绍了浅谈mysql双层not exists查询执行流程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、单个EXISTS、NOT EXISTS用法

DROP TABLE IF EXISTS `t_staff`;
CREATE TABLE `t_staff` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='人员表';
DROP TABLE IF EXISTS `t_major`;
CREATE TABLE `t_major` (
  `id` int(11) NOT NULL,
  `staff_id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='技能表';
INSERT INTO `t_staff` VALUES ('1', '张辽');
INSERT INTO `t_staff` VALUES ('2', '赵云');
INSERT INTO `t_staff` VALUES ('3', '夏侯渊');
INSERT INTO `t_major` VALUES ('1', '2', '大鹏展翅');
INSERT INTO `t_major` VALUES ('2', '2', '无敌风火轮');
INSERT INTO `t_major` VALUES ('3', '3', '横扫千军');

 EXISTS内层查询【非空】外层的where返回【真值】;内层查询【为空】外层的where返回【假值】
NOT EXISTS内层查询【非空】外层的where返回【假值】;内层查询【为空】外层的where返回【真值】

SELECT * FROM t_student_course WHERE TRUE;     --  能查出数据
SELECT * FROM t_student_course WHERE FALSE;    -- 不能查出数据

1、查询至少有一个技能的人员信息(in、EXISTS)

SELECT * FROM t_staff where id in (SELECT staff_id FROM t_major);
SELECT * FROM t_staff where EXISTS (
    SELECT 1 from t_major where t_staff.id = t_major.staff_id
);
-- 赵云、夏侯渊

2、查询一个技能都没有的人员信息(in、EXISTS)

SELECT * FROM t_staff where id not in (SELECT staff_id FROM t_major);
SELECT * FROM t_staff where NOT EXISTS (
    SELECT 1 from t_major where t_staff.id = t_major.staff_id
);
-- 张辽

二、EXISTS、NOT EXISTS(3张表)

DROP TABLE IF EXISTS `t_student`;
CREATE TABLE `t_student` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL COMMENT '姓名',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
DROP TABLE IF EXISTS `t_course`;
CREATE TABLE `t_course` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL COMMENT '课程名称',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
DROP TABLE IF EXISTS `t_student_course`;
CREATE TABLE `t_student_course` (
  `id` int(11) NOT NULL,
  `sid` varchar(255) NOT NULL,
  `cid` varchar(255) NOT NULL,
  `score` decimal(10,0) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `t_student` VALUES (1, '赵子龙');
INSERT INTO `t_student` VALUES (2, '关羽');
INSERT INTO `t_student` VALUES (3, '张飞');
INSERT INTO `t_student` VALUES (4, '黄忠');
INSERT INTO `t_student` VALUES (5, '马超');
INSERT INTO `t_course` VALUES (1, '语文');
INSERT INTO `t_course` VALUES (2, '数学');
INSERT INTO `t_course` VALUES (3, '英语');
INSERT INTO `t_student_course` VALUES (1, 1, 1, 95);
INSERT INTO `t_student_course` VALUES (2, 1, 2, 99);
INSERT INTO `t_student_course` VALUES (3, 1, 3, 100);
INSERT INTO `t_student_course` VALUES (4, 2, 1, 99);
INSERT INTO `t_student_course` VALUES (5, 2, 2, 100);
INSERT INTO `t_student_course` VALUES (6, 3, 2, 100);
INSERT INTO `t_student_course` VALUES (7, 3, 3, 95);
INSERT INTO `t_student_course` VALUES (8, 4, 1, 100);

EXISTS和NOT EXISTS相关子查询什么时候返回,返回有两个条件(很重要)。

1、子查询找到一个匹配的立即返回;
2、子查询遍历所有,没有找到一个匹配的返回为空。

 1、查询出选修了全部课程的学生姓名

SELECT name from t_student where id in(
    SELECT sid FROM t_student_course GROUP BY sid 
        HAVING (count(sid)) = (SELECT count(*) from t_course)
)  -- 记录一般写法
SELECT name from t_student s where NOT EXISTS (
    SELECT 1 from t_course c where NOT EXISTS (
        SELECT 1 from t_student_course sc 
            where sc.sid = s.id and sc.cid = c.id
    )
)
-- 赵子龙

 子查询只会返回true、false,select后面写1就行了。将查询语句定义成三个变量,后面好解释。

let a1 = SELECT 1 from t_student_course sc 
            where sc.sid = s.id and sc.cid = c.id
let b1 = SELECT 1 FROM t_role WHERE NOT EXISTS (a1)
let c1 = SELECT * FROM t_account WHERE NOT EXISTS (b1);

1  1 遍历sc表找到一个匹配的立即返回真,最内层的NOT EXISTS就为假,b1为空,不能返回
1  2 遍历sc表找到一个匹配的立即返回真,最内层的NOT EXISTS就为假,b1为空,不能返回
1  3 遍历sc表找到一个匹配的立即返回真,最内层的NOT EXISTS就为假,b1为空,不能返回
一个都没找就返回空,最外层的NOT EXISTS就为真,输出

2  1 遍历sc表找到一个匹配的立即返回真,最内层的NOT EXISTS就为假,b1为空,不能返回
2  2 遍历sc表找到一个匹配的立即返回真,最内层的NOT EXISTS就为假,b1为空,不能返回
2  3 遍历sc表没有找到一个匹配的返回空(假),最内层的NOT EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的NOT EXISTS就为假,不输出

3  1 遍历sc表没有找到一个匹配的返回空(假),最内层的NOT EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的NOT EXISTS就为假,不输出

4  1 遍历sc表找到一个匹配的立即返回真,最内层的NOT EXISTS就为假,b1为空,不能返回
4  2 遍历sc表没有找到一个匹配的返回空(假),最内层的NOT EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的NOT EXISTS就为假,不输出

5  1 遍历sc表没有找到一个匹配的返回空(假),最内层的NOT EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的NOT EXISTS就为假,不输出

2、查询至少选修了一门课程的学生

SELECT name from t_student s where EXISTS (
    SELECT 1 from t_course c where EXISTS (
        SELECT 1 from t_student_course sc 
              where sc.sid = s.id and sc.cid = c.id
    )
)
-- 赵子龙、关羽、张飞、黄忠

1  1 遍历sc表找到一个匹配的立即返回真,最内层的EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的EXISTS就为真,输出

2  1 遍历sc表找到一个匹配的立即返回真,最内层的EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的EXISTS就为真,输出

3  1 遍历sc表没有找到一个匹配的返回空,最内层的EXISTS就为假,b1为空,不能返回
3  2 遍历sc表找到一个匹配的立即返回真,最内层的EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的EXISTS就为真,输出

4  1 遍历sc表找到一个匹配的立即返回真,最内层的EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的EXISTS就为真,输出

5  1 遍历sc表没有找到一个匹配的返回空,最内层的EXISTS就为假,b1为空,不能返回
5  2 遍历sc表没有找到一个匹配的返回空,最内层的EXISTS就为假,b1为空,不能返回
5  3 遍历sc表没有找到一个匹配的返回空,最内层的EXISTS就为假,b1为空,不能返回

一个都没找就返回空,最外层的EXISTS就为假,不输出

3、查询没有选择所有课程的学生

SELECT name from t_student s where EXISTS (
    SELECT 1 from t_course c where NOT EXISTS (
        SELECT 1 from t_student_course sc 
            where sc.sid = s.id and sc.cid = c.id
    )
)
-- 关羽、张飞、黄忠、马超

1  1 遍历sc表找到一个匹配的立即返回真,最内层的NOT EXISTS就为假,b1为空,不能返回
1  2 遍历sc表找到一个匹配的立即返回真,最内层的NOT EXISTS就为假,b1为空,不能返回
1  3 遍历sc表找到一个匹配的立即返回真,最内层的NOT EXISTS就为假,b1为空,不能返回
一个都没找就返回空,最外层的EXISTS就为假,不输出

2  1 遍历sc表找到一个匹配的立即返回真,最内层的NOT EXISTS就为假,b1为空,不能返回
2  2 遍历sc表找到一个匹配的立即返回真,最内层的NOT EXISTS就为假,b1为空,不能返回
2  3 遍历sc表没有找到一个匹配的返回空(假),最内层的NOT EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的EXISTS就为真,输出

3  1 遍历sc表没有找到一个匹配的返回空(假),最内层的NOT EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的EXISTS就为真,输出

4  1 遍历sc表找到一个匹配的立即返回真,最内层的NOT EXISTS就为假,b1为空,不能返回
4  2 遍历sc表没有找到一个匹配的返回空(假),最内层的NOT EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的EXISTS就为真,输出

5  1 遍历sc表没有找到一个匹配的返回空(假),最内层的NOT EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的EXISTS就为假,不输出

4、查询一门课也没有选的学生

SELECT name FROM t_student s where NOT EXISTS (
    SELECT 1 from t_course c where EXISTS (
        SELECT 1 from t_student_course sc 
            where sc.sid = s.id and sc.cid = c.id
    )
)
-- 马超

1  1 遍历sc表找到一个匹配的立即返回真,最内层的EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的NOT EXISTS就为假,不输出

2  1 遍历sc表找到一个匹配的立即返回真,最内层的EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的NOT EXISTS就为假,不输出

3  1 遍历sc表没有找到一个匹配的返回空,最内层的EXISTS就为假,b1为空,不能返回
3  2 遍历sc表找到一个匹配的立即返回真,最内层的EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的NOT EXISTS就为假,不输出

4  1 遍历sc表找到一个匹配的立即返回真,最内层的EXISTS就为真,b1不为空,立即返回
找到一个匹配的立即返回真,最外层的NOT EXISTS就为假,不输出

5  1 遍历sc表没有找到一个匹配的返回空,最内层的EXISTS就为假,b1为空,不能返回
5  2 遍历sc表没有找到一个匹配的返回空,最内层的EXISTS就为假,b1为空,不能返回
5  3 遍历sc表没有找到一个匹配的返回空,最内层的EXISTS就为假,b1为空,不能返回

一个都没找就返回空,最外层的NOT EXISTS就为真,输出

5、查询至少选修了学生2选修的全部课程的学生名单

select * from t_student s where id != 2 and NOT EXISTS ( 
    select 1 from t_student_course sc where sid = 2 and NOT EXISTS ( 
        select 1 from t_student_course sc2 
            where sc2.cid = sc.cid and sc2.sid = s.id 
    ) 
)
-- 赵子龙

6、选出每门课程中成绩最高的学生

SELECT * FROM t_student_course sc 
    where sc.score = (SELECT max(score) FROM t_student_course sc2 
                        where sc2.cid = sc.cid)
SELECT * FROM t_student_course sc where NOT EXISTS (
    SELECT 1 FROM t_student_course sc2 
        where sc2.cid = sc.cid and sc2.score > sc.score
)

id sid cid score
3    1    3    100
4    1    4    97
7    2    2    100
8    2    3    100
9    3    1    100
11    4    5    100

最后来说说EXISTS、IN用法
EXISTS查询:先执行一次外部查询,然后为外部查询返回的每一行执行一次子查询,如果外部查询返回100行记录,sql就将执行101次查询。
IN查询:先查询子查询,然后把子查询的结果放到外部查询中进行查询。IN语句在mysql中没有参数个数的限制,但是mysql中sql语句有长度大小限制,整段最大为4M。IN引导的子查询只能返回一个字段。

EXISTS、IN怎么用
当子查询的表大的时候,使用EXISTS可以有效减少总的循环次数来提升速度,当外查询的表大的时候,使用IN可以有效减少对外查询表循环遍历来提升速度,
显然,外表大而子表小时,IN的效率更高,而外表小,子表大时,EXISTS的效率更高,若两表差不多大,则差不多。

到此这篇关于浅谈mysql双层not exists查询执行流程的文章就介绍到这了,更多相关mysql双层not exists内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • centos 6.4下使用rpm离线安装mysql

    centos 6.4下使用rpm离线安装mysql

    这篇文章主要为大家详细介绍了centos 6.4下使用rpm离线安装mysql的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • mysql 批量查询取每一组最新一条数据

    mysql 批量查询取每一组最新一条数据

    根据车牌号查询最新的一条交车记录的‘合同号’ ,这里只需要查询‘合同号’这个字段,这篇文章主要介绍了mysql 批量查询取每一组最新一条数据,需要的朋友可以参考下
    2024-02-02
  • mysql的join查询和多次查询方式比较

    mysql的join查询和多次查询方式比较

    这篇文章主要介绍了mysql的join查询和多次查询方式的比较,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Mysql Update批量更新的几种方式

    Mysql Update批量更新的几种方式

    今天小编就为大家分享一篇关于Mysql Update批量更新的几种方式,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • MySQL实战窗口函数SQL分析班级学生考试成绩及生活消费

    MySQL实战窗口函数SQL分析班级学生考试成绩及生活消费

    这篇文章主要为大家介绍了MySQL实战,利用窗口函数SQL来分析班级学生的考试成绩及生活消费的示例过程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2021-10-10
  • MySQL核心参数优化文件my.ini实现

    MySQL核心参数优化文件my.ini实现

    本文主要介绍了MySQL核心参数优化文件my.ini实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • MySQL5.7.03 更换高版本到MySQL 5.7.17安装过程及发现问题解决方案

    MySQL5.7.03 更换高版本到MySQL 5.7.17安装过程及发现问题解决方案

    这篇文章主要介绍了MySQL5.7.03 更换高版本到MySQL 5.7.17安装过程及发现问题解决方案,需要的朋友可以参考下
    2017-08-08
  • Suse Linux 10中MySql安装与配置步骤

    Suse Linux 10中MySql安装与配置步骤

    这篇文章主要介绍了Suse Linux 10中MySql安装与配置步骤,本文详细的讲解了安装步骤,需要的朋友可以参考下
    2015-05-05
  • 关于MySQL中savepoint语句使用时所出现的错误

    关于MySQL中savepoint语句使用时所出现的错误

    这篇文章主要介绍了关于MySQL中savepoint语句使用时所出现的错误,字符串出现e时所产生的问题也被作为MySQL的bug进行过提交,需要的朋友可以参考下
    2015-05-05
  • mysql如何配置secure_file_priv

    mysql如何配置secure_file_priv

    这篇文章主要介绍了mysql如何配置secure_file_priv问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01

最新评论