我的简化版本查询如下所示:
SELECT id
FROM table
WHERE column1
IN
(
SELECT column1
FROM table
GROUP BY column1
HAVING COUNT(*) > 1
)
这将选择id列表,其中column1具有多次出现的值(换句话说,这些不是唯一的)。这按预期工作,但有一个例外:如果值NULL多次出现(这是可能的),则不选择任何ID。如果NULL结果是非唯一的,那么选择列的id的正确方法是什么?
答案 0 :(得分:2)
使用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
);
WR抑制NULL:如果WHERE ex.column1 = tt.column1
或ex.column1
(或两者)碰巧为NULL,tt.column1
子句将始终返回false。
更新。看起来OP也希望元组带有column1 IS NULL
,如果有更多的元组。简单的解决方案是使用sentinel值(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
);
另一种(显而易见的)方法是明确检查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
);