SQL中NOT IN與NOT EXISTS不等價(jià)的問題
在對SQL語句進(jìn)行性能優(yōu)化時(shí),經(jīng)常用到一個(gè)技巧是將IN改寫成EXISTS,這是等價(jià)改寫,并沒有什么問題。問題在于,將NOT IN改寫成NOT EXISTS時(shí),結(jié)果未必一樣。
執(zhí)行環(huán)境:MySQL
一、舉例驗(yàn)證
例如,有如下一張表 rr 。要求:選擇4月2號的數(shù)據(jù),并且其type1是4月1號沒有的(從表看,就是4月2號C的那條)。

使用NOT IN ,單純按照這個(gè)條件去實(shí)現(xiàn)
select * from rr where create_date='2024-04-02' and type1 not in ( select type1 from rr where create_date='2024-04-01' ) ;

使用NOT EXISTS
select r1.* from rr as r1 where r1.create_date='2024-04-02' and not exists ( select r2.type1 from rr as r2 where r2.create_date='2024-04-01' and r1.type1=r2.type1 ) ;

主要原因是4月1號的數(shù)據(jù)中,存在type1為NULL的。如果該type1不是NULL,使用NOT IN就可以正確找出來結(jié)果了。
其中的原理涉及三值邏輯。
二、三值邏輯簡述
以下的式子都會(huì)被判為unknown
1、 = NULL
2、> NULL
3、< NULL
4、<> NULL
NULL = NULL
unknown,它是因關(guān)系數(shù)據(jù)庫采用了NULL而被引入的“第三個(gè)真值”。
(這里還有一點(diǎn)需要注意:真值unknown和作為NULL的一種UNKNOWN(未知)是不同的東西。前者是明確的布爾類型的真值,后者既不是值也不是變量。為了便于區(qū)分,前者采用粗體小寫字母unknown,后者用普通的大寫字母UNKNOWN表示。)
加上true和false,這三個(gè)真值之間有下面這樣的優(yōu)先級順序。
- AND 的情況:false > unknown > true
- OR 的情況:true > unknown > false
下面看具體例子,連同unknown一起理解下

三、附錄:用到的SQL
(運(yùn)行環(huán)境Mysql)
1、表 rr 的構(gòu)建
-- 使用了with語句 with rr as ( select '2024-04-01' as create_date,'A' as type1,001 as code1 union all select '2024-04-01' as create_date,'A' as type1,002 as code1 union all select '2024-04-01' as create_date,'A' as type1,002 as code1 union all select '2024-04-01' as create_date,'B' as type1,013 as code1 union all select '2024-04-01' as create_date,null as type1,013 as code1 union all select '2024-04-02' as create_date,'B' as type1,013 as code1 union all select '2024-04-02' as create_date,'C' as type1,109 as code1 union all select '2024-04-03' as create_date,'A' as type1,002 as code1 union all select '2024-04-04' as create_date,'A' as type1,002 as code1 )
2、 unknown的理解
set @a:=2, @b:=5, @c:= NULL ;
select @a+@b as result1,
case when (@b>@c) is true then 'true!'
when (@b>@c) is false then 'false!'
else 'unknown'
end as result2, -- 與NULL比較
case when (@a<@b and @b>@c) is true then 'true!'
when (@a<@b and @b>@c) is false then 'false!'
else 'unknown'
end as result3, -- and條件下 的優(yōu)先級展示
case when (@a<@b or @b>@c) is true then 'true!'
when (@a<@b or @b>@c) is false then 'false!'
else 'unknown'
end as result4, -- or條件下 的優(yōu)先級展示
case when (not(@b<>@c)) is true then 'true!'
when (not(@b<>@c)) is false then 'false!'
else 'unknown'
end as result5到此這篇關(guān)于SQL中NOT IN與NOT EXISTS不等價(jià)的問題的文章就介紹到這了,更多相關(guān)SQL NOT IN與NOT EXISTS不等價(jià)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- sql語句優(yōu)化之用EXISTS替代IN、用NOT EXISTS替代NOT IN的語句
- MySQL: mysql is not running but lock exists 的解決方法
- mysql insert if not exists防止插入重復(fù)記錄的方法
- UCenter info: MySQL Query Error SQL:SELECT value FROM [Table]vars WHERE noteexists
- mysql not in、left join、IS NULL、NOT EXISTS 效率問題記錄
- sql not in 與not exists使用中的細(xì)微差別
- Mysql中in和exists的區(qū)別?&?not?in、not?exists、left?join的相互轉(zhuǎn)換問題
相關(guān)文章
五種SQL Server分頁存儲(chǔ)過程的方法及性能比較
本文主要介紹了SQL Server數(shù)據(jù)庫分頁的存儲(chǔ)過程的五種方法以及它們之間性能的比較,并給出了詳細(xì)的代碼,希望能夠?qū)δ兴鶐椭?/div> 2015-08-08
數(shù)據(jù)庫 MySQL中文亂碼解決辦法總結(jié)
這篇文章主要介紹了數(shù)據(jù)庫 MySQL中文亂碼解決辦法總結(jié)的相關(guān)資料,數(shù)據(jù)庫保存中文字符,所以經(jīng)常遇到數(shù)據(jù)庫亂碼情況,這里提供了幾種方法,需要的朋友可以參考下2017-03-03
MSSQL 2005/2008 日志壓縮清理方法小結(jié)
本教程會(huì)詳細(xì)介紹下MSSQL 2005和MSSQL 2008刪除或壓縮數(shù)據(jù)庫日志的方法,感興趣的朋友可以參考下哈,希望可以幫助到你2013-03-03
SQL Server驅(qū)動(dòng)和TLS版本不兼容的原因分析和解決方案
這篇文章主要介紹了在將Java程序部署到Docker容器時(shí),由于SQL Server和OpenJDK 8之間的TLS/SSL版本不兼容問題導(dǎo)致的錯(cuò)誤,通過修改`java.security`文件放寬TLS/SSL的安全限制,解決了本地服務(wù)器和Docker容器的兼容性問題,需要的朋友可以參考下2025-11-11
在SQL?SERVER?中用SSMS實(shí)現(xiàn)每日自動(dòng)調(diào)用存儲(chǔ)過程的操作步驟
在SSMS中通過SQL?Server代理作業(yè)實(shí)現(xiàn)每日自動(dòng)調(diào)用存儲(chǔ)過程,需啟用服務(wù)、創(chuàng)建作業(yè)并配置每日調(diào)度計(jì)劃,注意權(quán)限與日志設(shè)置,測試驗(yàn)證后可擴(kuò)展多步驟及失敗通知功能,本文給大家介紹在SQL?SERVER中用SSMS實(shí)現(xiàn)每日自動(dòng)調(diào)用存儲(chǔ)過程的操作步驟,感興趣的朋友一起看看吧2025-08-08
SQLServer 優(yōu)化SQL語句 in 和not in的替代方案
用IN寫出來的SQL的優(yōu)點(diǎn)是比較容易寫及清晰易懂,這比較適合現(xiàn)代軟件開發(fā)的風(fēng)格。2010-04-04最新評論

