Sélectionnez l'instruction pour trouver des doublons dans certains champs

415

Pouvez-vous m'aider avec les instructions SQL pour trouver des doublons sur plusieurs champs?

Par exemple, en pseudo code:

select count(field1,field2,field3) 
from table 
where the combination of field1, field2, field3 occurs multiple times

et à partir de la déclaration ci-dessus s'il y a plusieurs occurrences, je voudrais sélectionner chaque enregistrement, sauf le premier .

JOE SKEET
la source
3
votre pseudo-code est ambigu, en plus vous ne définissez pas l'ordre selon lequel vous ne voulez pas le premier. je vous suggère de donner quelques exemples de données.
Unreason

Réponses:

840

Pour obtenir la liste des champs pour lesquels il existe plusieurs enregistrements, vous pouvez utiliser ..

select field1,field2,field3, count(*)
  from table_name
  group by field1,field2,field3
  having count(*) > 1

Consultez ce lien pour plus d'informations sur la suppression des lignes.

http://support.microsoft.com/kb/139444

Edit: Comme les autres utilisateurs l'ont mentionné, il devrait y avoir un critère pour décider comment vous définissez les "premières lignes" avant d'utiliser l'approche du lien ci-dessus. Sur cette base, vous devrez utiliser une clause order by et une sous-requête si nécessaire. Si vous pouvez publier des exemples de données, cela aiderait vraiment.

Rajesh Chamarthi
la source
42

Vous mentionnez "le premier", donc je suppose que vous avez une sorte de commande sur vos données. Supposons que vos données soient classées par un champ ID.

Ce SQL devrait vous procurer les entrées en double, à l'exception de la première. Il sélectionne essentiellement toutes les lignes pour lesquelles une autre ligne avec (a) les mêmes champs et (b) un ID inférieur existe. Les performances ne seront pas excellentes, mais cela pourrait résoudre votre problème.

SELECT A.ID, A.field1, A.field2, A.field3
  FROM myTable A
 WHERE EXISTS (SELECT B.ID
                 FROM myTable B
                WHERE B.field1 = A.field1
                  AND B.field2 = A.field2
                  AND B.field3 = A.field3
                  AND B.ID < A.ID)
Heinzi
la source
17

C'est une solution amusante avec SQL Server 2005 que j'aime. Je vais supposer que par "pour chaque enregistrement à l'exception du premier", vous voulez dire qu'il y a une autre colonne "id" que nous pouvons utiliser pour identifier quelle ligne est "première".

SELECT id
    , field1
    , field2
    , field3
FROM
(
    SELECT id
        , field1
        , field2
        , field3
        , RANK() OVER (PARTITION BY field1, field2, field3 ORDER BY id ASC) AS [rank]
    FROM table_name
) a
WHERE [rank] > 1
Nick Vaccaro
la source
Je viens de remarquer la balise SQL Server 2008. Heureux que ma suggestion soit toujours valable.
Nick Vaccaro
1
Excellente solution car elle retourne également les lignes qui devront être supprimées du tableau en question
Realto619
1
il est utile de considérer la liste de champs PARTITION BY comme une liste de champs PK
bkwdesign
6

Pour voir les valeurs en double:

with MYCTE  as (
    select row_number() over ( partition by name  order by name) rown, *
    from tmptest  
    ) 
select * from MYCTE where rown <=1
manoj Verma
la source
3

Si vous utilisez SQL Server 2005 ou version ultérieure (et les balises de votre question indiquent SQL Server 2008), vous pouvez utiliser des fonctions de classement pour renvoyer les enregistrements en double après le premier si l'utilisation de jointures est moins souhaitable ou peu pratique pour une raison quelconque. L'exemple suivant le montre en action, où il fonctionne également avec des valeurs nulles dans les colonnes examinées.

create table Table1 (
 Field1 int,
 Field2 int,
 Field3 int,
 Field4 int 
)

insert  Table1 
values    (1,1,1,1)
        , (1,1,1,2)
        , (1,1,1,3)
        , (2,2,2,1)
        , (3,3,3,1)
        , (3,3,3,2)
        , (null, null, 2, 1)
        , (null, null, 2, 3)

select    *
from     (select      Field1
                    , Field2
                    , Field3
                    , Field4
                    , row_number() over (partition by   Field1
                                                      , Field2
                                                      , Field3
                                         order by       Field4) as occurrence
          from      Table1) x
where     occurrence > 1

Notez après avoir exécuté cet exemple que le premier enregistrement de chaque "groupe" est exclu et que les enregistrements avec des valeurs nulles sont traités correctement.

Si vous n'avez pas de colonne disponible pour classer les enregistrements dans un groupe, vous pouvez utiliser les colonnes partitionnées comme colonnes de classement.

Bradford Hoagland
la source
1
CREATE TABLE #tmp
(
    sizeId Varchar(MAX)
)

INSERT  #tmp 
    VALUES ('44'),
        ('44,45,46'),
        ('44,45,46'),
        ('44,45,46'),
        ('44,45,46'),
        ('44,45,46'),
        ('44,45,46')


SELECT * FROM #tmp
DECLARE @SqlStr VARCHAR(MAX)

SELECT @SqlStr = STUFF((SELECT ',' + sizeId
              FROM #tmp
              ORDER BY sizeId
              FOR XML PATH('')), 1, 1, '') 


SELECT TOP 1 * FROM (
select items, count(*)AS Occurrence
  FROM dbo.Split(@SqlStr,',')
  group by items
  having count(*) > 1
  )K
  ORDER BY K.Occurrence DESC    
Mr.X
la source
0

essayez cette requête pour avoir le nombre de séparations de chaque instruction SELECT:

select field1,count(field1) as field1Count,field2,count(field2) as field2Counts,field3, count(field3) as field3Counts
from table_name
group by field1,field2,field3
having count(*) > 1
daryosh setorg
la source