【问题标题】:How to list all duplicated rows which may include NULL columns?如何列出所有可能包含 NULL 列的重复行?
【发布时间】:2011-03-02 00:23:24
【问题描述】:

我在列出包含 NULL 列的重复行时遇到问题。让我先说明我的问题。

USE [tempdb];
GO

IF OBJECT_ID(N'dbo.t') IS NOT NULL
BEGIN
    DROP TABLE dbo.t
END
GO

CREATE TABLE dbo.t
(
    a NVARCHAR(8),
    b NVARCHAR(8)
);
GO

INSERT t VALUES ('a', 'b');
INSERT t VALUES ('a', 'b');
INSERT t VALUES ('a', 'b');
INSERT t VALUES ('c', 'd');
INSERT t VALUES ('c', 'd');
INSERT t VALUES ('c', 'd');
INSERT t VALUES ('c', 'd');
INSERT t VALUES ('e', NULL);
INSERT t VALUES (NULL, NULL);
INSERT t VALUES (NULL, NULL);
INSERT t VALUES (NULL, NULL);
INSERT t VALUES (NULL, NULL);
GO

现在我想显示与其他行重复的所有行,我使用以下查询。

SELECT a, b
FROM   dbo.t
GROUP
    BY a, b
HAVING count(*) > 1

这会给我们结果:

a        b
-------- --------
NULL     NULL
a        b
c        d

现在如果我想列出所有导致重复的行,我使用这个查询:

WITH
duplicate (a, b) AS
(
    SELECT a, b
    FROM   dbo.t
    GROUP
        BY a, b
    HAVING count(*) > 1
)
SELECT dbo.t.a, dbo.t.b
FROM   dbo.t
       INNER JOIN duplicate
           ON (dbo.t.a = duplicate.a
           AND dbo.t.b = duplicate.b)

这会给我结果:

a        b
-------- --------
a        b
a        b
a        b
c        d
c        d
c        d
c        d

如您所见,所有包含 NULL 的行都会被过滤。我认为的原因是我使用等号来测试条件(dbo.t.a = duplicate.a AND dbo.t.b = duplicate.b),并且不能使用等号比较NULL。因此,为了在最后一个结果中包含包含 NULL 的行,我已将上述查询更改为

WITH
duplicate (a, b) AS
(
    SELECT a, b
    FROM   dbo.t
    GROUP
        BY a, b
    HAVING count(*) > 1
)
SELECT dbo.t.a, dbo.t.b
FROM   dbo.t
       INNER JOIN duplicate
           ON (dbo.t.a = duplicate.a
               AND dbo.t.b = duplicate.b)
           OR
           (dbo.t.a IS NULL
               AND duplicate.a IS NULL
               AND dbo.t.b = duplicate.b)
           OR
           (dbo.t.b IS NULL
               AND duplicate.b IS NULL
               AND dbo.t.a = duplicate.a)
           OR
           (dbo.t.a IS NULL
               AND duplicate.a IS NULL
               AND dbo.t.b IS NULL
               AND duplicate.b IS NULL)

这个查询会给我想要的答案:

a        b
-------- --------
NULL     NULL
NULL     NULL
NULL     NULL
NULL     NULL
a        b
a        b
a        b
c        d
c        d
c        d
c        d

现在我的问题是,如您所见,此查询仅包含两列,为了在最后一个结果中包含 NULL,您必须在查询中使用许多条件测试语句。随着列数的增加,您在查询中需要的条件测试语句也在惊人地增加。我该如何解决这个问题?

非常感谢。

【问题讨论】:

    标签: sql-server sql-server-2005 tsql duplicates


    【解决方案1】:

    您可以改用 OVER 子句:

    select a, b from
    (
        select a, b,
            COUNT(*) over (partition by a, b) Cnt
        from dbo.t
    ) TheResult
    where Cnt > 1
    

    这样你就可以避免所有条件,只需在子查询中添加所有字段并在主选择中检索它们。

    【讨论】:

      【解决方案2】:

      如果问题确实在于等号和NULL 值,SET ANSI_NULLS(将其设置为OFF)应该/可以解决问题。

      SET ANSI_NULLS OFF
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-02
        相关资源
        最近更新 更多