2009-04-08 11 views
2

J'ai une requête qui renvoie un jeu de résultats similaire à celui ci-dessous (en réalité, il est beaucoup plus, des milliers de lignes):éliminer les lignes en double partielles de jeu de résultats

 
    A | B | C | D 
    -----|----|----|----- 
1 NULL | d0 | d0 | NULL 
2 NULL | d0 | d1 | NULL 
3 NULL | d0 | d2 | a0 
4  d0 | d1 | d1 | NULL 
5  d0 | d2 | d2 | a0 

Deux des lignes sont considérées duplique, 1 et 2, car A, B et D sont identiques. Pour éliminer cela, je pourrais utiliser SELECT DISTINCT A, B, D, mais je n'obtiens pas la colonne C dans mon jeu de résultats. La colonne C est nécessaire pour les lignes d'information 3, 4 et 5.

Alors, comment puis-je viens de l'ensemble des résultats ci-dessus à celui-ci (le résultat apparaissant en C4 peut aussi être NULL au lieu de d1):

 
    A | B | C | D 
    -----|----|------|----- 
1 NULL | d0 | NULL | NULL 
3 NULL | d0 | d2 | a0 
4  d0 | d1 | d1 | NULL 
5  d0 | d2 | d2 | a0 
+0

A, B et D sont des colonnes qui définissent unicité? – gbn

+0

Et la colonne C peut être ignorée pour les doublons? – gbn

Répondre

5
DECLARE @YourTable TABLE (
    A VARCHAR(2) 
    , B VARCHAR(2) 
    , C VARCHAR(2) 
    , D VARCHAR(2)) 

INSERT INTO @YourTable VALUES (NULL, 'd0', 'd0', NULL) 
INSERT INTO @YourTable VALUES (NULL, 'd0', 'd1', NULL) 
INSERT INTO @YourTable VALUES (NULL, 'd0', 'd2', 'a0') 
INSERT INTO @YourTable VALUES ('d0', 'd1', 'd1', NULL) 
INSERT INTO @YourTable VALUES ('d0', 'd2', 'd2', 'a0') 


SELECT A, B, C = MIN(C), D 
FROM @YourTable 
GROUP BY A, B, D 

SELECT A, B, CASE WHEN MIN(C) = MAX(C) THEN MIN(C) ELSE NULL END, D 
FROM @YourTable 
GROUP BY A, B, D 

SELECT A, B, CASE WHEN MIN(COALESCE(C, 'dx')) = MAX(COALESCE(C, 'dx')) THEN MIN(C) ELSE NULL END, D 
FROM @YourTable 
GROUP BY A, B, D 
+0

+1 - GROUP BY existe pour combiner des lignes "similaires" qui partagent la même valeur d'un sous-ensemble de colonnes, et est donc exactement ce que l'OP demande. –

+0

Si la colonne C est la même pour les lignes 1 et 2, ou si une valeur est NULL, cela ne donne pas NULL. Cela fonctionne si les 2 valeurs de la colonne C sont différentes et à la fois NOT NULL – gbn

+0

... ce qui n'est pas défini par OP – gbn

0

Une sous-requête peut-être?

CHOISIR A, B, C, D à partir de la table 1 O EX EXISTE (CHOISIR DISTINCT A, B, D FROM table1);

+0

Testé cela? Juste donne 5 lignes: l'existant donnera soit toutes les lignes, soit aucune ligne) – gbn

0

si vous avez un identifiant unique dans la table, alors je pencherais pour quelque chose comme ceci:

 
SELECT A,B,C,D FROM table WHERE id IN (SELECT DISTINCT A,B,D) 

Le problème est que vous toujours obtenir la première valeur de C, le premier avec un valeur.

0

Le fait que vous ayez des valeurs NULL dans A et D compense les problèmes pour les EXISTS.

Toute solution MIN/MAX sur C peut ne pas vous donner NULL comme je pense que vous voulez. Sinon, utilisez MIN (C) et un groupe simple par.

Vous devez extraire les clés uniques premier (A, B, D), utilisez alors que, pour déterminer l'extrait les lignes à nouveau et travailler ce qu'il faut faire avec C

DECLARE @TheTable TABLE (
    A varchar(2) NULL, 
    B varchar(2) NULL, 
    C varchar(2) NULL, 
    D varchar(2) NULL 
) 

INSERT INTO @TheTable VALUES (NULL, 'd0', 'd0', NULL) 
INSERT INTO @TheTable VALUES (NULL, 'd0', 'd1', NULL) 
INSERT INTO @TheTable VALUES (NULL, 'd0', 'd2', 'a0') 
INSERT INTO @TheTable VALUES ('d0', 'd1', 'd1', NULL) 
INSERT INTO @TheTable VALUES ('d0', 'd2', 'd2', 'a0') 

SELECT DISTINCT 
    T.A, 
    T.B, 
    CASE Number WHEN 1 THEN T.C ELSE NULL END, 
    T.D 
FROM 
    (SELECT 
     COUNT(*) AS Number, 
     A, B, D 
    FROM 
     @TheTable 
    GROUP BY 
     A, B, D 
    ) UQ 
    JOIN 
    @TheTable T ON ISNULL(T.A, '') = ISNULL(UQ.A, '') AND ISNULL(T.B, '') = ISNULL(UQ.B, '') AND ISNULL(T.D, '') = ISNULL(UQ.D, '') 
2

Utilisez Dense_Rank() pour partitionner par A , B et D
(Merci Lieven, pour la requête de table temporaire, je devais l'utiliser pour la démo d'être cohérent;))

Selon MSDN,

Le rang d'une ligne est un plus le nombre de rangs distincts qui viennent avant la ligne en question

Cloisonnement par A, B, C puis le tri par A, B, C, D vous donnera le rang de 1 pour la première valeur distincte où l'unicité est défini par A, B, D. C'est de là que vient le filtrage par 1.

où DenseRank = 1

Voici le résultat

alt text

Voici le code:

DECLARE @YourTable TABLE (
    A VARCHAR(2) 
    , B VARCHAR(2) 
    , C VARCHAR(2) 
    , D VARCHAR(2)) 

INSERT INTO @YourTable VALUES (NULL, 'd0', 'd0', NULL) 
INSERT INTO @YourTable VALUES (NULL, 'd0', 'd1', NULL) 
INSERT INTO @YourTable VALUES (NULL, 'd0', 'd2', 'a0') 
INSERT INTO @YourTable VALUES ('d0', 'd1', 'd1', NULL) 
INSERT INTO @YourTable VALUES ('d0', 'd2', 'd2', 'a0') 

;with DistinctTable as (
    select *, 
    DenseRank = Dense_Rank() over (Partition By A, B, D order by A, B, C, D) 
    from @YourTable 
) 
select A, B, C, D 
from DistinctTable 
where DenseRank = 1 
Questions connexes