2

J'ai hérité d'une base de données SQL Server contenant des données en double. Je dois trouver et supprimer les lignes en double. Mais sans un champ d'identification, je ne suis pas sûr de savoir comment trouver les lignes.Comment trouver des doublons dans une table sans clé primaire ou champ ID?

Normalement, je le compare avec lui-même en utilisant un LEFT JOIN et vérifie que tous les champs sont les mêmes, sauf le champ ID serait table1.id <> table2.id, mais sans cela, je ne sais pas comment trouver des lignes en double et ne pas l'avoir aussi correspondre sur lui-même.

TABLE:

productId int not null, 
categoryId int not null, 
state varchar(255) not null, 
dateDone DATETIME not null 

DONNÉES ÉCHANTILLON

1, 3, "started", "2016-06-15 04:23:12.000" 
2, 3, "started", "2016-06-15 04:21:12.000" 
1, 3, "started", "2016-06-15 04:23:12.000" 
1, 3, "done", "2016-06-15 04:23:12.000" 

Dans cet exemple, seules les lignes 1 et 3 sont des doubles.

Comment trouver des doublons?

+1

Vous pouvez utiliser un cte ajouter un 'row_number()' avec la partition, puis supprimez où no_lig> 1 Je travaillerai sur – Matt

+0

exemple Pouvez-vous donner @ Matt un exemple? –

+0

Tous là pour vous, vos données de test, sélectionnez avant et après la suppression. Une note de côté si vous êtes en mesure de modifier le schéma, vous pouvez toujours ajouter une colonne d'identité plus tard. – Matt

Répondre

5

Utilisation ayant (et groupe par)

select 
    productId 
    , categoryId 
    , state 
    , dateDone 
    , count(*) 
from your_table 
group by productId ,categoryId ,state, dateDone 
having count(*) >1 
+1

Cette requête n'a pas travail. Il donne beaucoup de résultats qui ne sont pas des doublons –

+0

J'ai mis à jour la réponse avec le cont (*). ainsi vous pouvez vérifier si la rangée groupée est dupliquée ou pas .. autrement. .. laissez-moi voir un échantillon approprié .. et je vérifie pour le bon résultat. – scaisEdge

0

Vous pouvez CTE et limiter la sélection proprement dite du CTERN = 1. Voici la requête: -

;WITH ACTE 
AS 
(
    SELECT ProductID, categoryID, State, DateDone, 
    RN = ROW_NUMBER() OVER(PARTITION BY ProductID, CategoryID, State, DateDone 
          ORDER BY ProductID, CategoryID, State, DateDone) 
    FROM [Table] 
) 

SELECT * FROM ACTE WHERE RN = 1  
+0

essayez http://www.dpriver.com/pp/sqlformat.htm pour formater votre requête de manière plus lisible. –

+0

Merci fera l'affaire! – Mark

1

Pour une raison que je les croyais que tu voulais supprimer, je suppose que je lis que mal mais juste passer SUPPRIMER dans ma déclaration SELECT et maintenant vous avez tous les doublons et non l'original . Mais l'utilisation de DELETE supprimera tous les doublons et vous laissera toujours 1 enregistrement que je soupçonne être votre désir.

IF OBJECT_ID('tempdb..#TT') IS NOT NULL 
    BEGIN 
     DROP TABLE #TT 
    END 

CREATE TABLE #TT (
    productId int not null, 
    categoryId int not null, 
    state varchar(255) not null, 
    dateDone DATETIME not null 
) 

INSERT INTO #TT (productId, categoryId, state, dateDone) 
VALUES (1, 3, 'started', '2016-06-15 04:23:12.000') 
,(2, 3, 'started', '2016-06-15 04:21:12.000') 
,(1, 3, 'started', '2016-06-15 04:23:12.000') 
,(1, 3, 'done', '2016-06-15 04:23:12.000') 


SELECT * 
FROM 
    #TT 

;WITH cte AS (
    SELECT 
     * 
     ,RowNum = ROW_NUMBER() OVER (PARTITION BY productId, categoryId, state, dateDone ORDER BY productId) --note what you order by doesn't matter 

    FROM 

      #TT 
    ) 

--if you want to delete them just do this otherwise change DELETE TO SELECT 
    DELETE 
    FROM 
     cte 
    WHERE 
     RowNum > 1 

    SELECT * 
    FROM 
     #TT 

Si vous voulez et peut changer le schéma, vous pouvez toujours ajouter une colonne d'identité après le fait aussi, et il alimente le dossier existant

ALTER TABLE #TT 
ADD Id INTEGER IDENTITY(1,1) NOT NULL 
+0

Avez-vous un violon SQL pour cela? Je ne pouvais pas le faire fonctionner –

+0

Quel DB utilisez-vous? vous avez essayé sql-server, sql-server2008, 2012, 2005, etc SQL Fiddle est MySQL ... Si vous copiez tout dans la première case et collez dans SQL 2012 (qui a été étiqueté) SSMS il devrait fonctionner pour vous et le I Je suis assez sûr que les fonctionnalités que j'utilise remontent à 2005, je l'ai écrit dans SSMS en 2014. http://sqlmag.com/blog/window-functions-over-clause-help-make-difference – Matt

+0

SQL Fiddle peut aussi faire SQL Server (c'est dans le coin supérieur gauche pour le changer).Ils ont ces bases de données pour quelques clients différents et ils sont tous sur des versions différentes de SQL Server. C'est pourquoi je l'ai marqué comme ça. –

1

Vous pouvez le faire avec des fonctions de fenêtrage. Par exemple

create table #tmp 
    (
     Id INT 
    ) 


insert into #tmp 
VALUES (1), (1), (2) --so now we have duplicated rows 



WITH CTE AS 
    (
    SELECT 
     ROW_NUMBER() OVER(PARTITION BY Id ORDER BY Id) AS [DuplicateCounter], 
     Id 
    FROM #tmp 
    ) 
DELETE FROM CTE 
WHERE DuplicateCounter > 1 --duplicated rows have DuplicateCounter > 1