web-dev-qa-db-fra.com

T-SQL: Supprimer toutes les lignes en double mais en garder une

Duplicate possible:
SQL - Comment puis-je supprimer les lignes en double?

J'ai une table avec une très grande quantité de lignes. Les doublons ne sont pas autorisés, mais en raison d'un problème de création des lignes, je sais qu'il y a des doublons dans ce tableau. Je dois éliminer les lignes supplémentaires du point de vue des colonnes clés. Certaines autres colonnes peuvent avoir légèrement des données différentes, mais cela ne me dérange pas. J'ai encore besoin de garder une de ces lignes cependant. SELECT DISTINCT ne fonctionnera pas car il fonctionne sur toutes les colonnes et je dois supprimer les doublons en fonction des colonnes de clé.

Comment puis-je supprimer les lignes supplémentaires tout en en conservant une efficacement?

244
nuit9

Vous n'avez pas indiqué la version que vous utilisiez, mais dans SQL 2005 et versions ultérieures, vous pouvez utiliser une expression de table commune avec la clause OVER . C'est un peu comme ça:

WITH cte AS (
  SELECT[foo], [bar], 
     row_number() OVER(PARTITION BY foo, bar ORDER BY baz) AS [rn]
  FROM TABLE
)
DELETE cte WHERE [rn] > 1

Jouez avec et voyez ce que vous obtenez.

(Édition: pour tenter de vous aider, quelqu'un a édité la clause ORDER BY dans le CTE. Pour être clair, vous pouvez commander par tout ce que vous voulez ici, il ne doit pas nécessairement s'agir d'une des colonnes renvoyées par le cte. En fait, un cas d'utilisation courant ici est que "foo, bar" est l'identifiant du groupe et "baz" est une sorte d'horodatage. Pour conserver les dernières informations, vous feriez ORDER BY baz desc)

487
Ben Thul

Exemple de requête:

DELETE FROM Table
WHERE ID NOT IN
(
SELECT MIN(ID)
FROM Table
GROUP BY Field1, Field2, Field3, ...
)

Ici, fields sont des colonnes sur lesquelles vous souhaitez regrouper les lignes en double.

103
jams

Voici ma version, avec un exemple exploitable. Note Cela ne fonctionnera que dans la situation où Id est unique et que vous avez des valeurs en double dans d'autres colonnes.

DECLARE @SampleData AS TABLE (Id int, Duplicate varchar(20))

INSERT INTO @SampleData
SELECT 1, 'ABC' UNION ALL
SELECT 2, 'ABC' UNION ALL
SELECT 3, 'LMN' UNION ALL
SELECT 4, 'XYZ' UNION ALL
SELECT 5, 'XYZ'

DELETE FROM @SampleData WHERE Id IN (
    SELECT Id FROM (
        SELECT 
            Id
            ,ROW_NUMBER() OVER (PARTITION BY [Duplicate] ORDER BY Id) AS [ItemNumber]
            -- Change the partition columns to include the ones that make the row distinct
        FROM 
            @SampleData
    ) a WHERE ItemNumber > 1 -- Keep only the first unique item
)

SELECT * FROM @SampleData

Et les résultats:

Id          Duplicate
----------- ---------
1           ABC
3           LMN
4           XYZ

Je ne sais pas pourquoi c'est ce que je pensais d'abord… Ce n'est certainement pas la solution la plus simple, mais cela fonctionne.

23
Cᴏʀʏ