0

(私の単純化されたバージョンの)クエリは次のようになります。

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

これにより、column1 に複数の値が含まれる ID のリストが選択されます (つまり、これらは一意ではありません)。これは、1 つの例外を除いて期待どおりに機能します。値 NULL が複数回発生する場合 (これは可能です)、ID は選択されません。NULL が一意ではないことが判明した場合に列の ID を選択する正しい方法は何でしょうか?

4

1 に答える 1

2

EXISTS: existsの代わりに使用INする方が明確で (IMHO)、ほとんどの場合は高速です。(IN (...)重複とNULLを削除/抑制する必要があるため、セットをソートします)

この特定のケースでは、集計サブクエリは、 group 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 NULL の抑制:いずれか(または両方) が NULL であるWHERE ex.column1 = tt.column1場合、句は常に falseになります。ex.column1tt.column1


アップデート。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
);

もう 1 つの (明らかな) 方法は、明示的に NULL をチェックすることですが、これには次のような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
);
于 2013-09-28T14:45:29.290 に答える