sql語法巧用之not取反( 二 )


3. sql語法巧用我們知道,一個sql的bool表達式,有true/false之分 , 正常情況下都是以 true 作為判斷條件的 。比如 is null 為true, 那么 is not null 就為false 。=1為true, 那么 !=false, in 為true, 那么 not in 就為false 。between 為true, 那么 not between 就為false.
雖然情況很多,但是我們已經看到,sql中天然就有一個詞代表了取反的意思 。只是好像只有特定的場景下才可以使用not關鍵詞 。好像有點失望了 。
為什么不試一試呢?比如 x=1 的反義詞是否可以是 not x = 1 ? 為測試方便,我們直接使用內存數據庫sqllite測試, https://www.sqlite.org/download.html 。參考下載鏈接: https://www.sqlite.org/2022/sqlite-tools-win32-x86-3390400.zip
接下來我們用兩張表測試下 。
-- 新建測試表1create table test1 (id int, name varchar(50),age int)-- comment '用戶基礎信息表';-- 新建測試表2create table test2 (uid int,salary double,company varchar(50))-- comment '用戶工作信息表';-- 插入測試數據insert into test1 (id, name, age) values (1, 'zhangsan', 18);insert into test1 (id, name, age) values (2, 'lisi', 20);insert into test1 (id, name, age) values (3, 'wanger', 30);insert into test2 (uid, salary, company) values (1, 1000.1, 'axxx');insert into test2 (uid, salary, company) values (2, 2000.1, 'bxxx');insert into test2 (uid, salary, company) values (3, 3000.1, 'cxxx');接下來我們用not語法和非not語法測試下 。
sqlite> select * from test1 where name = 'zhangsan';1|zhangsan|18sqlite> select * from test1 where name != 'zhangsan';2|lisi|203|wanger|30sqlite> select * from test1 where not (name = 'zhangsan');2|lisi|203|wanger|30看起來語法是支持的,而且兩個語法的簡單語句執行結果居然是一樣的 。接下來我們測試稍微復雜點的:
sqlite> select * from test1 where name = 'zhangsan' or name = 'lisi';1|zhangsan|182|lisi|20sqlite> select * from test1 where name != 'zhangsan' and name != 'lisi';3|wanger|30sqlite> select * from test1 where not( name = 'zhangsan' or name = 'lisi');3|wanger|30看起來多個條件的連接not語法也是支持的,而且結果也是正確的呢 。我們來測試一個三條件的語句:
sqlite> select * from test1 where name = 'zhangsan' or name = 'lisi' and age = 20;1|zhangsan|182|lisi|20sqlite> select * from test1 where name != 'zhangsan' and (name != 'lisi' or age != 20);3|wanger|30sqlite> select * from test1 where not (name = 'zhangsan' or name = 'lisi' and age = 20);3|wanger|30sqlite> select * from test1 where age > 20;3|wanger|30sqlite> select * from test1 where age <= 20;1|zhangsan|182|lisi|20sqlite> select * from test1 where not( age > 20 );1|zhangsan|182|lisi|20好吧,看起來單表的操作并沒有問題 。會不會是因為單表簡單的原因?我們試試多表join的:
sqlite> select t1.name,t1.age, t2.salary from test1 t1 left join test2 t2 on t1.id = t2.uid where t1.age >= 20 and t2.salary > 2000;lisi|20|2000.1wanger|30|3000.1sqlite> select t1.name,t1.age, t2.salary from test1 t1 left join test2 t2 on t1.id = t2.uid where t1.age < 20 or t2.salary <= 2000;zhangsan|18|1000.1sqlite> select t1.name,t1.age, t2.salary from test1 t1 left join test2 t2 on t1.id = t2.uid where not (t1.age >= 20 and t2.salary > 2000);zhangsan|18|1000.1是了,沒問題,語法支持,結果正確 。換成其他的sql類數據庫做同樣的測試,仍然一致 ?;究梢源_定,not語法是可以覆蓋結果取反的場景的 。
4. not語法的底層原理雖然not語法看起來沒啥問題,但是在官方的介紹里,貌似并沒有找到相應的章節描述,為什么呢?不得而知 。
那么sql的not在底層是怎么實現的呢?兩個思路吧:一是像咱們前面提到的進行反面條件轉換,得到后再進行執行;二是直接計算的時候,先正向計算出結果,然后遇到not之后 , 當作一個運算符,直接將結果取反 , 從而決定結果是拋棄還是保留 。
因為數據庫底層都是是根據規則依次計算結果判定,所以最合適的方式是正向計算結果,然后遇到not進行true/false反轉,這是其正常的執行引擎流程 。但具體是否如此,暫不得而知,待以后有機會再研究研究 。
通過本文的介紹,在以后的工作中,咱們也可以多了一個選擇了,雖然少見,但不排除遇見 。希望能為大家多一點參考 。
【sql語法巧用之not取反】

推薦閱讀