2010-06-10 74 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