一段很繞的SQL(雙重否定)
?
??? 前段時間看到一段SQL,感覺實現的邏輯非常繞,而且看了之后想了很久都沒有想明白到底是怎么回事,再一直想到我都能記住這段SQL的具體細節了,放到博客上研究一下。以下模擬環境:
?
create table t1 (a int,b int);
insert into t1 values(1,1);
insert into t1 values(1,2);
insert into t1 values(1,3);
insert into t1 values(2,2);
insert into t1 values(2,3);
insert into t1 values(4,1);
insert into t1 values(4,2);
insert into t1 values(4,3);
insert into t1 values(5,1);
insert into t1 values(5,6);
insert into t1 values(6,1);
commit;
?
SQL> select * from t1;
?
??? A???? B
----- -----
??? 1???? 1
??? 1???? 2
??? 1???? 3
??? 2???? 2
??? 2???? 3
??? 4???? 1
??? 4???? 2
??? 4???? 3
??? 5???? 1
??? 5???? 6
??? 6???? 1
11 rows selected
?
?
??? 問題是這樣的:t1表中A代表人員編號,B代表事件編號。要求出t1表中所有包含人員2所對應的事件的人員編號。
??? 它給出的答案是這樣的:
?
select distinct a
? from t1 a
where not exists (select 1
????????? from t1 b
???????? where a = '2'
?????????? and not exists (select 1
????????????????? from t1 c
???????????????? where c.a = a.a
?????????????????? and c.b = b.b));
?
?
??? 首先可以確定的是結果肯定是正確的。然后來看一下邏輯:這段SQL中用了兩層not exists,是用雙重否定來取出最終結果的,但是具體的邏輯始終沒有看明白,到網上搜索了一下,發現遇到這個問題的人還挺多,找了個比較能夠看懂的解答看了下,總算明白了點:
?
?
?
?
?
??? 關于這道題目可能需要這樣來理解:
?
??? 1、先看最內層
?
??? select *
????? from t1 b
???? where a = '2'
?????? and not exists (select 1 from t1 c where c.b = b.b)
?
??? 這個代表人員2對應的事件中,沒有任何人對應的集合,很顯然是一個空集,因為即便沒有任何人對應,也有人員2自己對應。但是如果在c中加一個人員號的限定條件就不一定存在值了。
?
??? 2、在最內層中加上a限定
?
??? select *
????? from t1 b
???? where a = '2'
?????? and not exists (select 1
????????????? from t1 c
???????????? where c.a = &a
?????????????? and c.b = b.b)
??? 這就表示人員&a對應的事件中,沒有和人員2對應事件相同的事件集合。所以只要在這個查詢中沒有值的,即表示這個人員對應的事件包含了所有人員2對應的事件。如果有值則表示人員2對應的事件有1件或1件以上是該人員所沒有的。
?
??? 3、最外層就比較明顯了
?
??? select distinct a
????? from t1 a
???? where not exists (select 1
????????????? from t1 b
???????????? where a = '2'
?????????????? and not exists (select 1
????????????????????? from t1 c
???????????????????? where c.a = a.a
?????????????????????? and c.b = b.b))
??? 用最外層的a.a代替了&a,即把所有人員都進行比對,凡事在下面不存在值的(剛才判斷過了,不存在值即包含了2對應的所有事件),即需要獲取的人員信息。
???
?