从子查询中接收的值列表中选择,可能为null

时间:2013-09-28 14:33:47

标签: mysql sql unique

我的简化版本查询如下所示:

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

这将选择id列表,其中column1具有多次出现的值(换句话说,这些不是唯一的)。这按预期工作,但有一个例外:如果值NULL多次出现(这是可能的),则不选择任何ID。如果NULL结果是非唯一的,那么选择列的id的正确方法是什么?

1 个答案:

答案 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.column1ex.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
);