web-dev-qa-db-fra.com

Comment supprimer les lignes en double dans le serveur SQL?

Comment puis-jedelete duplicate rowsoù aucun unique row id n'existe?

Ma table est

col1  col2 col3 col4 col5 col6 col7
john  1    1    1    1    1    1 
john  1    1    1    1    1    1
sally 2    2    2    2    2    2
sally 2    2    2    2    2    2

Je souhaite conserver les éléments suivants après la suppression de la copie:

john  1    1    1    1    1    1
sally 2    2    2    2    2    2

J'ai essayé quelques requêtes mais je pense qu'elles dépendent d'un identifiant de ligne car je n'obtiens pas le résultat souhaité. Par exemple:

DELETE FROM table WHERE col1 IN (
    SELECT id FROM table GROUP BY id HAVING ( COUNT(col1) > 1 )
)
297
Fearghal

J'aime les CTE et ROW_NUMBER car les deux combinés nous permettent de voir quelles lignes sont supprimées (ou mises à jour), il suffit donc de changer le DELETE FROM CTE... en SELECT * FROM CTE:

WITH CTE AS(
   SELECT [col1], [col2], [col3], [col4], [col5], [col6], [col7],
       RN = ROW_NUMBER()OVER(PARTITION BY col1 ORDER BY col1)
   FROM dbo.Table1
)
DELETE FROM CTE WHERE RN > 1

DEMO (le résultat est différent; je suppose que c'est dû à une faute de frappe de votre part)

COL1    COL2    COL3    COL4    COL5    COL6    COL7
john    1        1       1       1       1       1
sally   2        2       2       2       2       2

Cet exemple détermine les doublons dans une colonne unique col1 en raison de PARTITION BY col1. Si vous souhaitez inclure plusieurs colonnes, ajoutez-les simplement au PARTITION BY:

ROW_NUMBER()OVER(PARTITION BY Col1, Col2, ... ORDER BY OrderColumn)
688
Tim Schmelter

Je préférerais que CTE supprime les lignes en double de la table du serveur SQL

recommande vivement de suivre cet article :: http://codaffection.com/sql-server-article/delete-duplicate-rows-in-sql-server/

en gardant l'original

WITH CTE AS
(
SELECT *,ROW_NUMBER() OVER (PARTITION BY col1,col2,col3 ORDER BY col1,col2,col3) AS RN
FROM MyTable
)

DELETE FROM CTE WHERE RN<>1

sans garder l'original

WITH CTE AS
(SELECT *,R=RANK() OVER (ORDER BY col1,col2,col3)
FROM MyTable)
 
DELETE CTE
WHERE R IN (SELECT R FROM CTE GROUP BY R HAVING COUNT(*)>1)
114
Shamseer K

Sans utiliser CTE et ROW_NUMBER(), vous pouvez simplement supprimer les enregistrements simplement en utilisant group by with MAX et voici un exemple

DELETE
FROM MyDuplicateTable
WHERE ID NOT IN
(
SELECT MAX(ID)
FROM MyDuplicateTable
GROUP BY DuplicateColumn1, DuplicateColumn2, DuplicateColumn3)
32
Aamir
DELETE from search
where id not in (
   select min(id) from search
   group by url
   having count(*)=1

   union

   SELECT min(id) FROM search
   group by url
   having count(*) > 1
)
13
Shoja Hamid

Microsoft propose un guide très soigné sur la manière de supprimer les doublons. Départ http://support.Microsoft.com/kb/139444

En bref, voici le moyen le plus simple de supprimer des doublons lorsque vous n’avez que quelques lignes à supprimer:

SET rowcount 1;
DELETE FROM t1 WHERE myprimarykey=1;

myprimarykey est l'identifiant de la ligne.

J'ai réglé rowcount sur 1 car je n'avais que deux lignes dupliquées. Si j'avais dupliqué 3 lignes, j'aurais réglé rowcount sur 2 pour qu'il supprime les deux premières qu'il voit et n'en laisse qu'une dans la table t1.

J'espère que ça aide quelqu'un

6
oabarca

S'il vous plaît voir le moyen de suppression ci-dessous aussi.

Declare @table table
(col1 varchar(10),col2 int,col3 int, col4 int, col5 int, col6 int, col7 int)
Insert into @table values 
('john',1,1,1,1,1,1),
('john',1,1,1,1,1,1),
('sally',2,2,2,2,2,2),
('sally',2,2,2,2,2,2)

Crée un exemple de table nommé @table et le charge avec les données données.

 enter image description here

Delete  aliasName from (
Select  *,
        ROW_NUMBER() over (Partition by col1,col2,col3,col4,col5,col6,col7 order by col1) as rowNumber
From    @table) aliasName 
Where   rowNumber > 1

Select * from @table

 enter image description here

Remarque: Si vous donnez toutes les colonnes dans la partie Partition by, alors order by n'aura pas beaucoup de signification.

Je sais, la question a été posée il y a trois ans et ma réponse est une autre version de ce que Tim a publié.

5
Jithin Shaji

Après avoir essayé la solution suggérée ci-dessus, cela fonctionne pour les petites tables moyennes. Je peux suggérer cette solution pour les très grandes tables. puisqu'il fonctionne en itérations.

  1. Supprimer toutes les vues de dépendance de la LargeSourceTable
  2. vous pouvez trouver les dépendances en utilisant sql managment studio, faites un clic droit sur la table et cliquez sur "Afficher les dépendances" 
  3. Renommez la table: 
  4. sp_rename 'LargeSourceTable', 'LargeSourceTable_Temp'; GO
  5. Créez à nouveau la LargeSourceTable, mais maintenant, ajoutez une clé primaire avec toutes les colonnes qui définissent les duplications. Ajoutez WITH (IGNORE_DUP_KEY = ON)
  6. Par exemple: 

    CREATE TABLE [dbo].[LargeSourceTable] ( ID int IDENTITY(1,1), [CreateDate] DATETIME CONSTRAINT [DF_LargeSourceTable_CreateDate] DEFAULT (getdate()) NOT NULL, [Column1] CHAR (36) NOT NULL, [Column2] NVARCHAR (100) NOT NULL, [Column3] CHAR (36) NOT NULL, PRIMARY KEY (Column1, Column2) WITH (IGNORE_DUP_KEY = ON) ); GO

  7. Créez à nouveau les vues que vous avez déposées en premier lieu pour le nouveau tableau créé

  8. Maintenant, exécutez le script SQL suivant, vous verrez les résultats dans 1 000 000 de lignes par page. Vous pouvez modifier le nombre de lignes par page pour afficher les résultats plus souvent.

  9. Notez que je règle le IDENTITY_INSERT sur et en dehors parce que l’une des colonnes contient un identifiant incrémentiel automatique, que je copie également.

SET IDENTITY_INSERT LargeSourceTable ON DECLARE @PageNumber AS INT, @RowspPage AS INT DECLARE @TotalRows AS INT declare @dt varchar(19) SET @PageNumber = 0 SET @RowspPage = 1000000 select @TotalRows = count (*) from LargeSourceTable_TEMP

While ((@PageNumber - 1) * @RowspPage < @TotalRows )
Begin
    begin transaction tran_inner
        ; with cte as
        (
            SELECT * FROM LargeSourceTable_TEMP ORDER BY ID
            OFFSET ((@PageNumber) * @RowspPage) ROWS
            FETCH NEXT @RowspPage ROWS ONLY
        )

        INSERT INTO LargeSourceTable 
        (
             ID                     
            ,[CreateDate]       
            ,[Column1]   
            ,[Column2] 
            ,[Column3]       
        )       
        select 
             ID                     
            ,[CreateDate]       
            ,[Column1]   
            ,[Column2] 
            ,[Column3]       
        from cte

    commit transaction tran_inner

    PRINT 'Page: ' + convert(varchar(10), @PageNumber)
    PRINT 'Transfered: ' + convert(varchar(20), @PageNumber * @RowspPage)
    PRINT 'Of: ' + convert(varchar(20), @TotalRows)

    SELECT @dt = convert(varchar(19), getdate(), 121)
    RAISERROR('Inserted on: %s', 0, 1, @dt) WITH NOWAIT
    SET @PageNumber = @PageNumber + 1
End

SET IDENTITY_INSERT LargeSourceTable OFF

4
Moshe Taieb

Si vous n'avez pas de références, comme des clés étrangères, vous pouvez le faire. Je le fais souvent lorsque je teste des preuves de concept et que les données de test sont dupliquées.

SELECT DISTINCT [col1], [col2], [col3], [col4], [col5], [col6], [col7]

INTO [newTable]

;

Allez dans l'explorateur d'objets et supprimez l'ancienne table.

Renommez la nouvelle table avec le nom de l'ancienne.

3
Rhys
-- this query will keep only one instance of a duplicate record.
;WITH cte
     AS (SELECT ROW_NUMBER() OVER (PARTITION BY col1, col2, col3-- based on what? --can be multiple columns
                                       ORDER BY ( SELECT 0)) RN
         FROM   Mytable)



delete  FROM cte
WHERE  RN > 1
2
Hasan Shouman
     SELECT DISTINCT * FROM TABLE;

Cela supprimera toutes les lignes en double et ne vous fournira que les valeurs distinctes (lignes).

1
Prince_Prajwal

Si vous avez la possibilité d'ajouter temporairement une colonne à la table, voici une solution qui a fonctionné pour moi:

ALTER TABLE dbo.DUPPEDTABLE ADD RowID INT NOT NULL IDENTITY(1,1)

Puis effectuez un DELETE en combinant MIN et GROUP BY.

DELETE b
FROM dbo.DUPPEDTABLE b
WHERE b.RowID NOT IN (
                     SELECT MIN(RowID) AS RowID
                     FROM dbo.DUPPEDTABLE a WITH (NOLOCK)
                     GROUP BY a.ITEM_NUMBER,
                              a.CHARACTERISTIC,
                              a.INTVALUE,
                              a.FLOATVALUE,
                              a.STRINGVALUE
                 );

Vérifiez que le DELETE a fonctionné correctement:

SELECT a.ITEM_NUMBER,
    a.CHARACTERISTIC,
    a.INTVALUE,
    a.FLOATVALUE,
    a.STRINGVALUE, COUNT(*)--MIN(RowID) AS RowID
FROM dbo.DUPPEDTABLE a WITH (NOLOCK)
GROUP BY a.ITEM_NUMBER,
    a.CHARACTERISTIC,
    a.INTVALUE,
    a.FLOATVALUE,
    a.STRINGVALUE
ORDER BY COUNT(*) DESC 

Le résultat ne doit pas contenir de lignes dont le nombre est supérieur à 1. Enfin, supprimez la colonne rowid:

ALTER TABLE dbo.DUPPEDTABLE DROP COLUMN RowID;
1
j.hull

En référence à https://support.Microsoft.com/en-us/help/139444/how-to-remove-duplicate-rows-from-a-table-in-sql-server

L’idée de supprimer les doublons implique 

  • a) Protéger les lignes qui ne sont pas en double
  • b) Conservez l’une des nombreuses lignes qualifiées de doublons.

Pas à pas

  • 1) Commencez par identifier les lignes correspondant à la définition de dupliquer .__ et insérez-les dans la table temporaire, par exemple #tableAll.
  • 2) Sélectionnez des lignes non dupliquées (simples) ou distinctes dans la table temporaire Say #tableUnique.
  • 3) Supprimer de la table source en joignant #tableAll pour supprimer les doublons
  • 4) Insérez dans la table source toutes les lignes de #tableUnique.
  • 5) Supprimez #tableAll et #tableUnique
1
rajibdotnet
with myCTE
as

(
select productName,ROW_NUMBER() over(PARTITION BY productName order by slno) as Duplicate from productDetails
)
Delete from myCTE where Duplicate>1
1
Debendra Dash
DECLARE @TB TABLE(NAME VARCHAR(100));
INSERT INTO @TB VALUES ('Red'),('Red'),('Green'),('Blue'),('White'),('White')
--**Delete by Rank**
;WITH CTE AS(SELECT NAME,DENSE_RANK() OVER (PARTITION BY NAME ORDER BY NEWID()) ID FROM @TB)
DELETE FROM CTE WHERE ID>1
SELECT NAME FROM @TB;
--**Delete by Row Number** 
;WITH CTE AS(SELECT NAME,ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY NAME) ID FROM @TB)
DELETE FROM CTE WHERE ID>1;
SELECT NAME FROM @TB;
0
Surinder Singh

Vous devez regrouper les enregistrements en double en fonction du ou des champs, puis conserver l'un des enregistrements et supprimer le reste .

DELETE prg.Person WHERE Id IN ( SELECT dublicateRow.Id FROM ( select MIN(Id) MinId, NationalCode from prg.Person group by NationalCode having count(NationalCode ) > 1 ) GroupSelect JOIN prg.Person dublicateRow ON dublicateRow.NationalCode = GroupSelect.NationalCode WHERE dublicateRow.Id <> GroupSelect.MinId)

0
Hadi Salehy

La suppression de doublons d'une table énorme (plusieurs millions d'enregistrements) peut prendre un certain temps. Je suggère que vous fassiez une insertion en bloc dans une table temporaire des lignes sélectionnées plutôt que la suppression.

--REWRITING YOUR CODE(TAKE NOTE OF THE 3RD LINE) WITH CTE AS(SELECT NAME,ROW_NUMBER() 
OVER (PARTITION BY NAME ORDER BY NAME) ID FROM @TB) SELECT * INTO #unique_records FROM 
CTE WHERE ID =1;
0
Emmanuel Bull

Oh wow, je me sens si bête de préparer toutes ces réponses, ce sont des réponses d’experts avec tous les tableaux CTE et Temp, etc.

Et tout ce que j'ai fait pour que cela fonctionne est simplement agrégé la colonne ID en utilisant MAX.

DELETE FROM table WHERE col1 IN (
    SELECT MAX(id) FROM table GROUP BY id HAVING ( COUNT(col1) > 1 )
)

REMARQUE: vous devrez peut-être l'exécuter plusieurs fois pour supprimer les doublons, car cela ne supprimera qu'un seul ensemble de lignes en double à la fois.

0
messed-up

Pour ce faire, vous pouvez procéder de différentes manières sur SQL Server. La méthode la plus simple consiste à: insérer les différentes lignes de la table des lignes en double dans la nouvelle table temporaire. Supprimez ensuite toutes les données de la table de lignes en double, puis insérez toutes les données de la table temporaire ne contenant aucune copie, comme indiqué ci-dessous.

select distinct * into #tmp From table
   delete from table
   insert into table
   select * from #tmp drop table #tmp

   select * from table

Supprimer les lignes en double à l'aide de Common Table Expression (CTE)

With CTE_Duplicates as

(sélectionnez id, name, row_number () over (partition par id, nom par ordre, nom) numéro d'arrière-plan de la table) delete from CTE_Duplicates où rownumber! = 1

0

Une autre façon de supprimer les lignes en double sans perdre les informations en une étape est la suivante:

delete from dublicated_table t1 (nolock)
join (
    select t2.dublicated_field
    , min(len(t2.field_kept)) as min_field_kept
    from dublicated_table t2 (nolock)
    group by t2.dublicated_field having COUNT(*)>1
) t3 
on t1.dublicated_field=t3.dublicated_field 
    and len(t1.field_kept)=t3.min_field_kept
0
Tolga Gölelçin

Essayez d'utiliser: 

SELECT linkorder
    ,Row_Number() OVER (
        PARTITION BY linkorder ORDER BY linkorder DESC
        ) AS RowNum
FROM u_links

 enter image description here

0
Fezal halai