2010-06-10 72 views
1

我有列出包含NULL列的重复行的问题。首先让我看看我的问题。如何列出所有可能包含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 

正如你所看到的,所有的行都包括空值被过滤。我认为的原因是我使用等号来测试条件(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,你必须在查询中使用许多条件测试语句。随着列号的增加,您在查询中需要的条件测试语句惊人地增加。我怎么解决这个问题?

非常感谢。

回答

2

可以使用OVER子句来代替:

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

这样就可以避免所有的条件下,只需添加在子查询中所有的领域和检索他们的主要选择。

1

如果问题确实存在于等号和NULL值中,则SET ANSI_NULLS(将其设置为OFF)应该/可以做到这一点。

SET ANSI_NULLS OFF