淺談mysql雙層not exists查詢(xún)執(zhí)行流程
一、單個(gè)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', '無(wú)敵風(fēng)火輪'); INSERT INTO `t_major` VALUES ('3', '3', '橫掃千軍');
EXISTS內(nèi)層查詢(xún)【非空】外層的where返回【真值】;內(nèi)層查詢(xún)【為空】外層的where返回【假值】
NOT EXISTS內(nèi)層查詢(xún)【非空】外層的where返回【假值】;內(nèi)層查詢(xún)【為空】外層的where返回【真值】
SELECT * FROM t_student_course WHERE TRUE; -- 能查出數(shù)據(jù) SELECT * FROM t_student_course WHERE FALSE; -- 不能查出數(shù)據(jù)
1、查詢(xún)至少有一個(gè)技能的人員信息(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、查詢(xún)一個(gè)技能都沒(méi)有的人員信息(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 '課程名稱(chēng)', 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, '關(guān)羽'); INSERT INTO `t_student` VALUES (3, '張飛'); INSERT INTO `t_student` VALUES (4, '黃忠'); INSERT INTO `t_student` VALUES (5, '馬超'); INSERT INTO `t_course` VALUES (1, '語(yǔ)文'); INSERT INTO `t_course` VALUES (2, '數(shù)學(xué)'); INSERT INTO `t_course` VALUES (3, '英語(yǔ)'); 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相關(guān)子查詢(xún)什么時(shí)候返回,返回有兩個(gè)條件(很重要)。
1、子查詢(xún)找到一個(gè)匹配的立即返回;
2、子查詢(xún)遍歷所有,沒(méi)有找到一個(gè)匹配的返回為空。
1、查詢(xún)出選修了全部課程的學(xué)生姓名
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) ) -- 記錄一般寫(xiě)法 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 ) ) -- 趙子龍
子查詢(xún)只會(huì)返回true、false,select后面寫(xiě)1就行了。將查詢(xún)語(yǔ)句定義成三個(gè)變量,后面好解釋。
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表找到一個(gè)匹配的立即返回真,最內(nèi)層的NOT EXISTS就為假,b1為空,不能返回
1 2 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的NOT EXISTS就為假,b1為空,不能返回
1 3 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的NOT EXISTS就為假,b1為空,不能返回
一個(gè)都沒(méi)找就返回空,最外層的NOT EXISTS就為真,輸出2 1 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的NOT EXISTS就為假,b1為空,不能返回
2 2 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的NOT EXISTS就為假,b1為空,不能返回
2 3 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空(假),最內(nèi)層的NOT EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的NOT EXISTS就為假,不輸出3 1 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空(假),最內(nèi)層的NOT EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的NOT EXISTS就為假,不輸出4 1 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的NOT EXISTS就為假,b1為空,不能返回
4 2 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空(假),最內(nèi)層的NOT EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的NOT EXISTS就為假,不輸出5 1 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空(假),最內(nèi)層的NOT EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的NOT EXISTS就為假,不輸出
2、查詢(xún)至少選修了一門(mén)課程的學(xué)生
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 ) ) -- 趙子龍、關(guān)羽、張飛、黃忠
1 1 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的EXISTS就為真,輸出2 1 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的EXISTS就為真,輸出3 1 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空,最內(nèi)層的EXISTS就為假,b1為空,不能返回
3 2 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的EXISTS就為真,輸出4 1 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的EXISTS就為真,輸出5 1 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空,最內(nèi)層的EXISTS就為假,b1為空,不能返回
5 2 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空,最內(nèi)層的EXISTS就為假,b1為空,不能返回
5 3 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空,最內(nèi)層的EXISTS就為假,b1為空,不能返回一個(gè)都沒(méi)找就返回空,最外層的EXISTS就為假,不輸出
3、查詢(xún)沒(méi)有選擇所有課程的學(xué)生
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 ) ) -- 關(guān)羽、張飛、黃忠、馬超
1 1 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的NOT EXISTS就為假,b1為空,不能返回
1 2 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的NOT EXISTS就為假,b1為空,不能返回
1 3 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的NOT EXISTS就為假,b1為空,不能返回
一個(gè)都沒(méi)找就返回空,最外層的EXISTS就為假,不輸出2 1 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的NOT EXISTS就為假,b1為空,不能返回
2 2 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的NOT EXISTS就為假,b1為空,不能返回
2 3 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空(假),最內(nèi)層的NOT EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的EXISTS就為真,輸出3 1 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空(假),最內(nèi)層的NOT EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的EXISTS就為真,輸出4 1 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的NOT EXISTS就為假,b1為空,不能返回
4 2 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空(假),最內(nèi)層的NOT EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的EXISTS就為真,輸出5 1 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空(假),最內(nèi)層的NOT EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的EXISTS就為假,不輸出
4、查詢(xún)一門(mén)課也沒(méi)有選的學(xué)生
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表找到一個(gè)匹配的立即返回真,最內(nèi)層的EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的NOT EXISTS就為假,不輸出2 1 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的NOT EXISTS就為假,不輸出3 1 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空,最內(nèi)層的EXISTS就為假,b1為空,不能返回
3 2 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的NOT EXISTS就為假,不輸出4 1 遍歷sc表找到一個(gè)匹配的立即返回真,最內(nèi)層的EXISTS就為真,b1不為空,立即返回
找到一個(gè)匹配的立即返回真,最外層的NOT EXISTS就為假,不輸出5 1 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空,最內(nèi)層的EXISTS就為假,b1為空,不能返回
5 2 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空,最內(nèi)層的EXISTS就為假,b1為空,不能返回
5 3 遍歷sc表沒(méi)有找到一個(gè)匹配的返回空,最內(nèi)層的EXISTS就為假,b1為空,不能返回一個(gè)都沒(méi)找就返回空,最外層的NOT EXISTS就為真,輸出
5、查詢(xún)至少選修了學(xué)生2選修的全部課程的學(xué)生名單
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、選出每門(mén)課程中成績(jī)最高的學(xué)生
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
最后來(lái)說(shuō)說(shuō)EXISTS、IN用法
EXISTS查詢(xún):先執(zhí)行一次外部查詢(xún),然后為外部查詢(xún)返回的每一行執(zhí)行一次子查詢(xún),如果外部查詢(xún)返回100行記錄,sql就將執(zhí)行101次查詢(xún)。
IN查詢(xún):先查詢(xún)子查詢(xún),然后把子查詢(xún)的結(jié)果放到外部查詢(xún)中進(jìn)行查詢(xún)。IN語(yǔ)句在mysql中沒(méi)有參數(shù)個(gè)數(shù)的限制,但是mysql中sql語(yǔ)句有長(zhǎng)度大小限制,整段最大為4M。IN引導(dǎo)的子查詢(xún)只能返回一個(gè)字段。
EXISTS、IN怎么用
當(dāng)子查詢(xún)的表大的時(shí)候,使用EXISTS可以有效減少總的循環(huán)次數(shù)來(lái)提升速度,當(dāng)外查詢(xún)的表大的時(shí)候,使用IN可以有效減少對(duì)外查詢(xún)表循環(huán)遍歷來(lái)提升速度,
顯然,外表大而子表小時(shí),IN的效率更高,而外表小,子表大時(shí),EXISTS的效率更高,若兩表差不多大,則差不多。
到此這篇關(guān)于淺談mysql雙層not exists查詢(xún)執(zhí)行流程的文章就介紹到這了,更多相關(guān)mysql雙層not exists內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL無(wú)法存儲(chǔ)emoji表情解決方案分析
這篇文章主要介紹了MySQL無(wú)法存儲(chǔ)emoji表情解決方案,結(jié)合實(shí)例形式分析了Python爬蟲(chóng)爬取文章中emoji表情存入數(shù)據(jù)庫(kù)的實(shí)現(xiàn)方法,涉及mysql utf8mb4編碼的修改相關(guān)操作技巧,需要的朋友可以參考下2018-07-07MySQL 那些常見(jiàn)的錯(cuò)誤設(shè)計(jì)規(guī)范,你都知道嗎
今天來(lái)看一看 MySQL 設(shè)計(jì)規(guī)范中幾個(gè)常見(jiàn)的錯(cuò)誤例子,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-07-07mysql+shardingSphere的分庫(kù)分表實(shí)現(xiàn)示例
分庫(kù)分表是一種場(chǎng)景解決方案,它的出現(xiàn)是為了解決一些場(chǎng)景問(wèn)題的,本文主要介紹了mysql+shardingSphere的分庫(kù)分表實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以2024-04-04解決創(chuàng)建主鍵報(bào)錯(cuò):Incorrect column specifier for
這篇文章主要介紹了解決創(chuàng)建主鍵報(bào)錯(cuò):Incorrect column specifier for column‘id‘問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08mysql主從基于docker和django實(shí)現(xiàn)讀寫(xiě)分離
這篇文章主要介紹了mysql主從基于docker和django實(shí)現(xiàn)讀寫(xiě)分離,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下2022-08-08