Navicat 部落格

一些常見的 SQL 査詢錯誤 - 第 1 部分 2022 年 4 月 11 日,由 Robert Gravelle 撰寫

NOT IN 與 NOT EXISTS

在程式設計界,「反面模式(anti-pattern)」是一個常用術語。它指的是解決經常出現的問題的方法,而這方法不僅無效,而且有可能適得其反。這個術語最初是由電腦程式師 Andrew Koenig 於 1995 年在其著作《設計模式》中創造的,作為被認為既可靠又有效的設計模式的反義詞。

儘管 SQL 並不是一種真正的程式設計語言,但事實證明它同樣容易受到反面模式的影響,尤其是當間題中的查詢相當複雜時。有時錯誤很難被發現,直到查詢在生產環境中使用時,錯誤才會暴露出來。

為了儘早發現 SQL 錯誤,接下來的幾篇文章將重點介紹一些最常見的錯誤。我們將使用 MySQL 來作為今天的範例,但這些概念在任何類型的 SQL 中都同樣有效。

NOT IN 與 NOT EXISTS

一種常見類型的 SELECT 查詢可以擷取未包含在值清單中的資料。舉例來說,這裡有兩個在 Navicat for MySQL 16 中建立的非常簡單的資料表。第一個資料表儲存色彩資料:

colors (24K)

第二個資料表儲存產品資料:

products (15K)

我們想要做的是選取所有尚未與任何產品關聯的色彩。換句話說,我們需要建置一個查詢,只傳回那些產品沒有的色彩。我們可以嘗試使用 NOT IN 述詞來取得相關記錄。

我們預計以下查詢傳回兩列(「black」和「green」),而實際上它傳回的是一個空白結果集:

not_in (27K)

問題出在哪裡?products 資料表的 color 欄中存在 NULL 值,由 NOT IN 述詞轉換為:

color NOT IN (Red, Blue, NULL)

NOT(color=Red OR color=Blue OR color=NULL)

運算式「color=NULL」的計算結果為 UNKNOWN,許多資料庫開發人員忽略的是,NOT UNKNOWN 也計算結果為 UNKNOWN!結果,所有列都被過濾掉,查詢會傳回零列。

如果需求發生變化,這個問題也會浮出水面,並且會更新一個不可為 NULL 的欄為允許 NULL。因此,即使欄在初始設計中不允許使用 NULL,以防萬一你也應該確保查詢在使用 NULL 時繼續正常工作。

最簡單的解決方案是使用 EXISTS 述詞而不是 IN:

not_exists (39K)

問題解決了!

那麼,為什麼會這樣呢?IN 關鍵字將比較相應子查詢欄中的所有值,而 EXISTS 則評估真或假。因此,使用 IN 運算子時,SQL 引擎將掃描從內部查詢取得的所有記錄。另一方面,如果我們使用的是 EXISTS,SQL 引擎將在找到符合項目後立即停止掃描程序。

結論

在有關常見的 SQL 查詢錯誤的第一部分中,我們了解了反面模式如何出現在 SELECT 查詢中,首先是錯誤地使用 NOT IN 述詞。

如果你想試用 Navicat 16 for MySQL,你可以在這裡下載 14 天的試用版。

Navicat 文章
頻道記錄
分享
部落格封存檔