mysql中關(guān)鍵詞exists的用法實例詳解
前言
在日常開發(fā)中,用mysql進行查詢的時候,有一個比較少見的關(guān)鍵詞exists,我們今天來學(xué)習(xí)了解一下這個exists這個sql關(guān)鍵詞的用法,這樣在工作中遇到一些特定的業(yè)務(wù)場景就可以有更加多樣化的解決方案
語法解釋
語法
SELECT column1 FROM t1 WHERE [conditions] and EXISTS (SELECT * FROM t2 );
說明
括號中的子查詢并不會返回具體的查詢到的數(shù)據(jù),只是會返回true或者false,如果外層sql的字段在子查詢中存在則返回true,不存在則返回false
即使子查詢的查詢結(jié)果是null,只要是對應(yīng)的字段是存在的,子查詢中則返回true,下面有具體的例子
執(zhí)行過程
1、首先進行外層查詢,在表t1中查詢滿足條件的column1
2、接下來進行內(nèi)層查詢,將滿足條件的column1帶入內(nèi)層的表t2中進行查詢,
3、如果內(nèi)層的表t2滿足查詢條件,則返回true,該條數(shù)據(jù)保留
4、如果內(nèi)層的表t2不滿足查詢條件,則返回false,則刪除該條數(shù)據(jù)
5、最終將外層的所有滿足條件的數(shù)據(jù)進行返回
貼個鏈接,mysql官方對于這個命令的說明: https://dev.mysql.com/doc/refman/8.0/en/exists-and-not-exists-subqueries.html;喜歡看英文原版說明的可以來這里看一下
使用案例
環(huán)境準(zhǔn)備
?? mysql版本: 8.0.28
?? 數(shù)據(jù)庫表設(shè)計:
學(xué)生表: t_student
CREATE TABLE `t_student` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '學(xué)生姓名', `age` int NOT NULL COMMENT '年齡', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='學(xué)生表';
導(dǎo)入部分?jǐn)?shù)據(jù)
INSERT INTO `t_student` (`id`, `name`, `age`) VALUES (1, '小張', 10), (2, 'chenille', 13), (3, '小王', 15), (4, '小米', 11), (5, 'dong', 13), (6, 'xi', 12), (7, 'chenille', 13), (8, '小王地方', 15), (9, '米來', 11), (10, 'dong', 13), (11, '呵呵', 12), (12, 'chenille', 13), (13, '小趙', 15), (14, '小米-0', 11), (15, 'bei', 13), (16, 'xi-xx', 12), (17, 'chenille', 13), (18, '小王-hehe', 15), (19, '小米-qian', 11), (20, 'dong', 13), (21, 'xi', 12), (22, 'chenille', 13), (23, '小王-1', 15), (24, '小米-2', 11), (25, 'dong-3', 13), (26, 'xi-0', 12), (27, 'chenille-4', 13), (28, '小王-4', 15), (29, '小米-7', 11), (30, 'dong-1', 13), (31, 'xi-5', 12), (32, '貔貅', 10), (33, '耄耋', 12), (34, '饕餮', 9), (35, '龍', 13), (36, '青牛', 12);
班級學(xué)生表:t_class_student
CREATE TABLE `t_class_student` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `student_id` int NOT NULL COMMENT '學(xué)生ID', `class_id` int NOT NULL COMMENT '班號', `class_name` varchar(100) DEFAULT '' COMMENT '班級名稱', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='班級學(xué)生表';
導(dǎo)入部分?jǐn)?shù)據(jù)
INSERT INTO `t_class_student` (`id`, `student_id`, `class_id`, `class_name`) VALUES (1, 1, 1, '一年級1班'), (2, 2, 1, '一年級1班'), (3, 3, 1, '一年級1班'), (4, 4, 1, '一年級1班'), (5, 5, 1, '一年級1班'), (6, 6, 1, '一年級1班'), (7, 7, 1, '一年級1班'), (8, 8, 1, '一年級1班'), (9, 9, 1, '一年級1班'), (10, 10, 1, '一年級1班'), (11, 11, 2, '一年級2班'), (12, 12, 2, '一年級2班'), (13, 13, 2, '一年級2班'), (14, 14, 2, '一年級2班'), (15, 15, 2, '一年級2班'), (16, 16, 2, '一年級2班'), (17, 17, 2, '一年級2班'), (18, 18, 2, '一年級2班'), (19, 19, 2, '一年級2班'), (20, 20, 2, '一年級2班'), (21, 21, 3, '二年級2班'), (22, 22, 3, '二年級2班'), (23, 23, 3, '二年級2班'), (24, 24, 3, '二年級2班'), (25, 25, 3, '二年級2班'), (26, 26, 3, '二年級2班'), (27, 27, 3, '二年級2班'), (28, 28, 3, '二年級2班'), (29, 29, 3, '二年級2班'), (30, 30, 3, '二年級2班'), (31, 31, 4, '三年級1班'); (32, 32, 4, null);
常用查詢
已分配班級的學(xué)生名單 ??
select * from t_student as s where exists (select student_id from t_class_student where student_id = s.id);
未分配班級的學(xué)生名單 ??
select * from t_student as s where not exists (select student_id from t_class_student where student_id = s.id);
已分配 三年級1班 的學(xué)生名單 ??
select * from t_student as s where exists (select student_id from t_class_student where student_id = s.id and class_id = 4);
已分配 并且班級是 一年級1班 和 一年級2班 的學(xué)生名單 ??
select * from t_student as s where exists (select student_id from t_class_student where student_id = s.id and class_id in (1, 2) );
查詢到的字段為null,但是子查詢返回的結(jié)果為true ??
select * from t_student as s where exists (select class_name from t_class_student where student_id = s.id and class_id = 4);
查詢?nèi)繉W(xué)生名單 ??
select * from t_student as s where exists (select student_id from t_class_student where 1=1);
已分配 三年級1班 的并且年齡大于10歲的學(xué)生名單 ??
select * from t_student as s where age > 10 and exists (select student_id from t_class_student where student_id = s.id and class_id = 4);
exists與in的效率比較
上面的這些查詢其實也可以通過 in 關(guān)鍵字來實現(xiàn),下面我們寫一下 in 關(guān)鍵字對應(yīng)的查詢語句,
通過 in 實現(xiàn)已分配班級的學(xué)生名單 ??
select * from t_student as s where id in (select student_id from t_class_student where student_id = s.id);
通過 in 實現(xiàn)未分配班級的學(xué)生名單 ??
select * from t_student as s where id not in (select student_id from t_class_student where student_id = s.id);
下面我們來分析一下這兩個關(guān)鍵字使用效率到底那個更高呢?
循環(huán)嵌套查詢執(zhí)行原理
?? 循環(huán)由外向內(nèi),外層循環(huán)執(zhí)行一次,內(nèi)層循環(huán)則需要完整的執(zhí)行一次,內(nèi)層執(zhí)行執(zhí)行完后返回執(zhí)行結(jié)果,外層循環(huán)繼續(xù)執(zhí)行,直到外層循環(huán)完全執(zhí)行完成
循環(huán)優(yōu)化策略
?? 有了上面的執(zhí)行原理的說明,我們明白了一個道理:內(nèi)層循環(huán)次數(shù)的多少不會影響到外層的次數(shù),但是外層循環(huán)的次數(shù)直接會影響到內(nèi)層循環(huán)的次數(shù),外層循環(huán)每多一次,內(nèi)層循環(huán)就需要多完整的一次循環(huán),所以我們優(yōu)化的目標(biāo)其實就是使外層的循環(huán)次數(shù)盡量少,總結(jié)來說:小表驅(qū)動大表。小表就是外層循環(huán),大表就是內(nèi)層循環(huán),也就是盡量減少外層循環(huán)的次數(shù)
exists和in查詢原理的區(qū)別
?? exists : 外表先進行循環(huán)查詢,將查詢結(jié)果放入exists的子查詢中進行條件驗證,確定外層查詢數(shù)據(jù)是否保留
?? in : 先查詢內(nèi)表,將內(nèi)表的查詢結(jié)果當(dāng)做條件提供給外表查詢語句進行比較
結(jié)論
通過上面的優(yōu)化策略分析和exists和in的查詢原理的分析,將這兩塊內(nèi)容結(jié)合起來其實就得出了我們想要的一個結(jié)論:
外層小表,內(nèi)層大表(或者將sql從左到由來看:左面小表,右邊大表): exists 比 in 的效率高
外層大表,內(nèi)層小表(或者將sql從左到由來看:左面大表,右邊小表): in 比 exists 的效率高
參考資料
https://www.bilibili.com/video/BV1V64y1q7yi?spm_id_from=333.337.search-card.all.click
總結(jié)
上面我們簡單介紹了一下平時我們比較少用到的一個exists的關(guān)鍵字,通過一些使用的實例,大家也可以基本上了解了它的使用方法,在以后的日常工作中,我們在碰到一些查詢問題的時候,這個時候就有了更加多樣化的選擇方案啦
到此這篇關(guān)于mysql中關(guān)鍵詞exists用法的文章就介紹到這了,更多相關(guān)mysql exists用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL中的RIGHT?JOIN和CROSS?JOIN操作示例
本文詳細介紹了MySQL中的RIGHT?JOIN和CROSS?JOIN操作,RIGHT?JOIN返回右表中的所有記錄及與左表中的記錄相匹配的記錄,而CROSS?JOIN返回兩個表中所有可能的組合,通過實際示例和輸出結(jié)果,我們展示了如何使用RIGHT?JOIN和CROSS?JOIN進行數(shù)據(jù)庫查詢,一起看看吧2023-07-07在 Windows 10 上安裝 解壓縮版 MySql(推薦)
這篇文章主要介紹了在 Windows 10 上安裝 解壓縮版 MySql(推薦)的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-12-12內(nèi)網(wǎng)ssh/mysql登錄緩慢的解決方法
本文介紹了“內(nèi)網(wǎng)ssh/mysql登錄緩慢的解決方法”,需要的朋友可以參考一下2013-03-03