2013-09-28 58 views
0

一個看起來是這樣的:選擇從子查詢收到,可能是查詢(我的簡化版)空

SELECT id 
FROM table 
WHERE column1 
IN 
(
    SELECT column1 
    FROM table 
    GROUP BY column1 
    HAVING COUNT(*) > 1 
) 

這將選擇ID的名單,其中列1具有繁殖發生的歷史值(換句話說,這些不是唯一的)。這可以按預期工作,但有一個例外:如果值NULL出現多次(這是可能的),則不會選擇id。如果NULL結果是非唯一的,那麼選擇列ID的正確方法是什麼?

+0

有像COLUMN1指數(KEY(列1))? –

+0

你有一些示例數據嗎? –

回答

3

使用EXISTS而不是IN:存在更清晰(恕我直言),在大多數情況下它也更快。 (IN (...)需要刪除/抑制重複項和NULL,因此:對集進行排序)

在這種特殊情況下:聚合子查詢僅用於找出組count() > 1。查詢優化器可能沒有意識到這一點,並在將它們與1進行比較之前計算完整的組計數(在整個行集上)。

SELECT tt.id 
FROM thetable tt 
WHERE EXISTS (
    SELECT * FROM thetable ex 
    WHERE ex.column1 = tt.column1 AND ex.id <> tt.id 
); 

WRT空值的抑制:在WHERE ex.column1 = tt.column1子句將始終產生錯誤如果任ex.column1tt.column1(或兩者)碰巧是NULL。


UPDATE。看來,OP還希望column1 IS NULL的元組(如果有更多的元組)。簡單的解決方案是使用一個標記值(即本機不存在於columnn1的值),並使用該作爲替代:(在下面-1所述片段用作替代值)

SELECT tt.id 
FROM thetable tt 
WHERE EXISTS (
    SELECT * FROM thetable ex 
    WHERE COALESCE(ex.column1, -1) = COALESCE(tt.column1, -1) 
    AND ex.id <> tt.id 
); 

另一個(很明顯)的方法是明確地檢查空值,但是這將需要一個OR條款和一堆括號,如:

SELECT tt.id 
FROM thetable tt 
WHERE EXISTS (
    SELECT * FROM thetable ex 
    WHERE (ex.column1 = tt.column1 
      OR (ex.column1 IS NULL AND tt.column1 IS NULL) 
     ) 
    AND ex.id <> tt.id 
); 
+0

如果兩者碰巧都是NULL,它應該返回true。這就是整個問題的關鍵。我添加了或ISNULL(ex.column1)和ISNULL(tt.column1)。事情似乎現在正在起作用。 – user2180613

+0

Aha,在這種情況下,我回到了舊的繪圖板...(解決方案可能會涉及雙重否定)BTW:IN(子選擇)總是從結果集中刪除NULL(和重複)。 – wildplasser

+1

不,它不會,給予足夠的鑰匙/指數。 (根據月相的不同,聚合子查詢版本將需要或不需要完整掃描) – wildplasser