成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

NOT IN子查詢中出現NULL值對結果的影響你注意到了嗎

數據庫 其他數據庫
本文不是為了討論效率問題,是要提醒一點:not in子查詢的結果集含NULL值時,會導致整個語句結果集返回空,這可能造成與SQL語句書寫初衷不符。

前言

開發人員寫的SQL語句中經常會用到in,exists,not in,not exists 這類子查詢,通常,含in、exists的子查詢稱為半連接(semijoin),含not in、 not exists的子查詢被稱之為反連接,經常會有技術人員來評論in 與exists 效率孰高孰低的問題,我在SQL優化工作中也經常對這類子查詢做優化改寫,比如半連接改為內連接,反連接改為外連接等,哪個效率高是要根據執行計劃做出判斷的,本文不是為了討論效率問題,是要提醒一點:not in子查詢的結果集含NULL值時,會導致整個語句結果集返回空,這可能造成與SQL語句書寫初衷不符。

實驗

創建實驗表t1,t2


greatsql> create table t1(c1 int primary key,c2 varchar(10), key idx_c1(c2));
greatsql> create table t2(c1 int primary key,c2 varchar(10)),key idx_c1(c2));

greatsql> insert into t1 values(1,'a'),(2,'b');
greatsql> insert into t2 values(1,'a'),(2,'c');

觀察下面兩條語句:


select * from t1 where t1.c2 not in (select t2.c2 from t2);
select * from t1 where not exists (select 1 from t2 where t2.c2=t1.c2);

這兩個語句,從表達的含義來看是等價的,都是查詢t1表中c2列值在t2表的c2列值中不存在的記錄。

從子查詢類型來看,第一條語句屬于非關聯查詢,第二條語句屬于關聯子查詢。所謂非關聯子查詢就是子查詢中內查詢可以獨立執行,與外查詢沒有關系,互不影響。而關聯子查詢的執行依賴于外部查詢,通常情況下都是因為子查詢中的表用到了外部的表,并進行了條件關聯,因此每執行一次外部查詢,子查詢都要重新計算一次。

從連接類型來看,使用not in與not exists子查詢構造的語句都屬于反連接,為了控制連接順序與連接方式,這種反連接經常被改寫為外連接,t1 與t2使用左外連接,條件加上右表t2的連接列 is null,也就是左外連接時沒有關聯上右表的數據,表達了這個含義“t1表中c2列值在t2表的c2列值中不存在的記錄”。反連接改寫為外連接,不會導致關聯結果集放大,因為沒有關聯上的t1表數據只顯示1條,半連接改為內連接時要注意去重。外連接語句如下所示:


greatsql> select t1.* from t1 left join t2 on t1.c2=t2.c2 where t2.c2 is null;

所以本質表達含義上,上面的三條語句都等價。

下面看一下三條語句的執行結果:


greatsql> select * from t1 where t1.c2 not in (select t2.c2 from t2);
+----+------+
| c1 | c2   |
+----+------+
|  2 | b    |
+----+------+
1 row in set (0.00 sec)

greatsql> select * from t1 where not exists (select 1 from t2 where t2.c2=t1.c2);
+----+------+
| c1 | c2   |
+----+------+
|  2 | b    |
+----+------+
1 row in set (0.01 sec)

greatsql> select t1.* from t1 left join t2 on t1.c2=t2.c2 where t2.c2 is null;
+----+------+
| c1 | c2   |
+----+------+
|  2 | b    |
+----+------+
1 row in set (0.00 sec)

可以看出就目前的數據,三條語句執行結果是相同的。

下面向子查詢的t2中插入一條c2列為null的記錄。


greatsql> insert into t2 values(3,null);

再觀察一下三條語句的執行結果:


greatsql> select * from t1 where t1.c2 not in (select t2.c2 from t2);
Empty set (0.00 sec)

greatsql> select * from t1 where not exists (select 1 from t2 where t2.c2=t1.c2);
+----+------+
| c1 | c2   |
+----+------+
|  2 | b    |
+----+------+
1 row in set (0.00 sec)

greatsql> select t1.* from t1 left join t2 on t1.c2=t2.c2 where t2.c2 is null;
+----+------+
| c1 | c2   |
+----+------+
|  2 | b    |
+----+------+
1 row in set (0.00 sec)

可以看出,not exists表示的關聯子查詢與 外連接方式表達的兩條語句結果相同,而not in表示的非關聯子查詢的結果集為空。這是因為子查詢select t2.c2 from t2 查詢結果含有NULL值導致的。NULL屬于未知值,無法與其他值進行比較,無從判斷,返回最終結果集為空。這一點在MySQL與Oracle中返回結果都是一致的。如果想表達最初的含義,需要將子查詢中NULL值去除。


greatsql> select * from t1 where t1.c2 not in (select t2.c2 from t2 where t2.c2 is not null);
+----+------+
| c1 | c2   |
+----+------+
|  2 | b    |
+----+------+
1 row in set (0.02 sec)

那么如果t1表的c2列也插入一條NULL值的記錄后,結果集會怎樣呢,兩個表都存在c2列為NULL的值數據,那么t1表這條NULL值數據能否出現在最終結果集中呢?


greatsql> insert into t1 values(3,null);
Query OK, 1 row affected (0.07 sec)

greatsql> select * from t1 where t1.c2 not in (select t2.c2 from t2 where t2.c2 is not null);
+----+------+
| c1 | c2   |
+----+------+
|  2 | b    |
+----+------+
1 row in set (0.00 sec)

greatsql> select * from t1 where not exists (select 1 from t2 where t2.c2=t1.c2);
+----+------+
| c1 | c2   |
+----+------+
|  3 | NULL |
|  2 | b    |
+----+------+
2 rows in set (0.00 sec)

greatsql> select t1.* from t1 left join t2 on t1.c2=t2.c2 where t2.c2 is null;
+----+------+
| c1 | c2   |
+----+------+
|  3 | NULL |
|  2 | b    |
+----+------+
2 rows in set (0.00 sec)

從執行結果來看,使用not in非關聯子查詢,其執行結果與其他兩條語句的執行結果還是不同,因為t1.c2 使用not in在參與比較時就隱含了t1.c2 is not null的含義,所以最終結果集中不含(3,NULL)這條數據。

而not exists關聯子查詢,在將外查詢的NULL值傳遞給內查詢時執行子查詢 select * from t2 where t2.c2=NULL,子查詢中找不到記錄,所以條件返回false, 表示not exists 為true,則最終結果集中含(3,NULL)這條記錄。

左外left join 與 not exists相同,左表的NULL值在右表中關聯不上數據,所以要返回(3,NULL)這條數據。這里要注意NULL 不等于 NULL。


greatsql> select NULL=NULL;
+-----------+
| NULL=NULL |
+-----------+
|      NULL |
+-----------+
1 row in set (0.01 sec)

說到這里,GreatSQL支持<=>安全等于這個符號,用來判斷NULL值:當兩個操作數均為NULL時,其返回值為1而不為NULL;而當一個操作數為NULL時,其返回值為0而不為NULL。


greatsql> select NULL<=>NULL;
+-------------+
| NULL<=>NULL |
+-------------+
|           1 |
+-------------+
1 row in set (0.00 sec)

greatsql> select 1<=>NULL;
+----------+
| 1<=>NULL |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

所以not exists 子查詢中的=  換成 <=>  時,最終結果集中去除了(3,NULL)這條數據。


greatsql> select * from t1 where not exists (select 1 from t2 where t2.c2<=>t1.c2);
+----+------+
| c1 | c2   |
+----+------+
|  2 | b    |
+----+------+
1 row in set (0.00 sec)

注意,一般表關聯時不使用<=>安全等于這個符號,想象一下,如果關聯的兩個表在關聯字段上都存在很多NULL記錄,關聯后的結果集對NULL記錄的關聯是以笛卡爾積的形式體現的,嚴重影響效率,嚴格來說關聯字段都為NULL值不能算作能匹配上。

結論

使用not in 的非關聯子查詢注意NULL值對結果集的影響,為避免出現空結果集,需要子查詢中查詢列加 is not null條件將NULL值去除。

實際使用時注意:需求表達的含義是否要將外查詢關聯字段值為NULL的數據輸出,not in隱含了不輸出。

一般認為not exists關聯子查詢與外連接語句是等價的,可以進行相互改寫。

select * from t1 where not exists (select 1 from t2 where t2.c2=t1.c2);
   
   select t1.* from t1 left join t2 on t1.c2=t2.c2 where t2.c2 is null;

如果不需要輸出外查詢中關聯字段為NULL值的數據,還需再加條件 t1.c2 is not null。

select * from t1 where not exists (select 1 from t2 where t2.c2=t1.c2) and t1.c2 is not null;
   
   select t1.* from t1 left join t2 on t1.c2=t2.c2 where t2.c2 is null and t1.c2 is not null;

這樣寫就與select * from t1 where t1.c2 not in (select t2.c2 from t2 where t2.c2 is not null)等價了。

責任編輯:武曉燕 來源: GreatSQL社區
相關推薦

2012-11-19 10:30:08

win8

2022-12-02 08:47:36

2020-01-09 08:00:29

微信實用功能移動開發

2022-06-01 00:10:24

惡意軟件欺詐行為設備

2019-11-08 09:52:55

程序員技能開發者

2015-05-26 09:35:29

運維運維危機云計算應用

2022-07-11 08:48:52

業務轉型CIO

2020-04-14 08:46:47

Java對象編譯器

2009-06-12 12:37:38

Java軟件

2019-09-26 08:00:00

AI人工智能

2018-10-25 15:04:22

編程程序員陷阱

2018-03-15 15:09:29

iOS圖片標記蘋果

2021-09-03 06:46:34

MyBatis緩存后端

2011-06-28 09:16:11

切克簽到

2021-07-29 18:46:52

可視化類型圖形化

2021-05-12 13:38:47

云計算

2022-05-16 08:09:45

前端API

2022-09-09 10:15:06

OAuthJava

2024-11-14 10:57:41

vue子組件props

2021-10-25 08:48:21

客戶體驗CIOIT領導者
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩一区二区三区精品 | 国产综合在线视频 | 日日噜 | 久久精片 | 亚洲精品性视频 | 国产伊人精品 | 国产在线一区二区三区 | 日韩成人免费视频 | 污视频在线免费观看 | 亚洲精品欧美 | 在线免费看黄 | 天堂一区二区三区 | 成人超碰在线 | 中文字幕加勒比 | 久久99国产精品 | 91麻豆精品国产91久久久久久久久 | 亚洲欧美中文日韩在线v日本 | 国产精品免费在线 | 国产精品99视频 | 欧美日韩不卡合集视频 | 国产视频久久久 | 欧美极品一区二区 | 久久久久久久久99 | 紧缚调教一区二区三区视频 | 日韩中文字幕在线免费 | 久久精品一区 | 成人免费观看男女羞羞视频 | 久久国产高清 | 欧美日韩在线视频一区 | 亚洲最大的黄色网址 | 国产不卡在线 | 日韩精品视频一区二区三区 | 福利视频网站 | 国产精品日韩一区二区 | 一级黄色在线 | 青青久在线视频 | 日韩欧美在线播放 | 国产一区2区| 啪一啪| 成人在线中文字幕 | 久久久网|