2009-10-31 7 views
3

Comment puis-je supprimer des lignes dupliquées dans SQL Server 2008?Comment supprimer des lignes dupliquées dans SQL Server 2008?

+2

Évitez les en mettant les contraintes d'unicité dans votre base de données – Jherico

+0

@gold: si vous ne disposez pas d'une primaire clé, vous n'avez pas de table, fondamentalement. Aucune clé primaire ne signifie aucun moyen d'identifier de manière unique vos lignes. Ajouter une clé primaire - alors vous pouvez commencer à réparer vos autres problèmes. –

Répondre

4

Ajouter une clé primaire. Sérieusement, chaque table devrait en avoir une. Il peut s'agir d'une identité et vous pouvez l'ignorer, mais assurez-vous que chaque table possède une clé primaire définie.

Imaginez que vous avez une table comme:

create table T (
    id int identity, 
    colA varchar(30) not null, 
    colB varchar(30) not null 
) 

Ensuite, vous pouvez dire quelque chose comme:

delete T 
from T t1 
where exists 
(select null from T t2 
where t2.colA = t1.colA 
and t2.colB = t1.colB 
and t2.id <> t1.id) 

Une autre astuce est de sélectionner les enregistrements distincts avec l'identifiant minimum, et de garder les :

delete T 
where id not in 
(select min(id) from T 
group by colA, colB) 

(Désolé, je ne l'ai pas testé ces derniers, mais l'un des e idées ese pourrait vous conduire à votre solution)

Notez que si vous ne disposez pas d'une clé primaire, la seule façon de le faire est de tirer parti d'une pseudo-colonne comme ROWID -. mais je ne suis pas Assurez-vous que SQL Server 2008 offre cette idée.

0

En supposant que vous avez une clé primaire appelée id et d'autres colonnes sont col2 ... coln, et que par les lignes « en double » vous voulez dire toutes les lignes où toutes les valeurs de la colonne à l'exception du PK sont dupliquées

delete from A where id not in 
(select min(id) from A 
group by col2, col3, ...coln) as x 

-à-dire groupe sur toutes les colonnes non-PK

+0

ça ne fonctionne pas, parce que je n'ai pas de clé primaire. comment je peux le faire sans clé primaire? – Gold

11

La méthode la plus simple consiste à utiliser une expression CTE (Common Table Expression). J'utilise cette méthode quand j'ai des données brutes à importer; la première chose que je fais pour l'assainir est de s'assurer qu'il n'y a pas de doublons --- que j'ai une sorte de poignée unique à chaque ligne.

Résumé:

WITH numbered AS (
    SELECT ROW_NUMBER() OVER(PARTITION BY [dupe-column-list] ORDER BY [dupe-column-list]) AS _dupe_num FROM [table-name] WHERE 1=1 
) 
DELETE FROM numbered WHERE _dupe_num > 1; 

La partie « -colonne duper la liste » est l'endroit où vous la liste de toutes les colonnes impliquées où vous souhaitez les valeurs sont uniques. Le ORDER BY est l'endroit où vous décidez, dans un ensemble de doublons, quelle ligne "gagne" et qui est supprimée. (La "WHERE 1 = 1" est juste une habitude personnelle.)

La raison pour laquelle cela fonctionne est que Sql Server conserve une référence interne unique à chaque ligne source sélectionnée dans le CTE. Ainsi, lorsque le DELETE est exécuté, il connaît la ligne exacte à supprimer, peu importe ce que vous mettez dans la liste de sélection de votre CTE. (Si vous êtes nerveux, vous pouvez remplacer "DELETE" par "SELECT *", mais comme vous avez des lignes en double, cela ne va pas vous aider, si vous pouviez identifier chaque ligne de façon unique, vous ne liriez pas .)

Exemple:

CREATE TABLE ##_dupes (col1 int, col2 int, col3 varchar(50)); 
INSERT INTO ##_dupes 
    VALUES (1, 1, 'one,one') 
     , (2, 2, 'two,two') 
     , (3, 3, 'three,three') 
     , (1, 1, 'one,one') 
     , (1, 2, 'one,two') 
     , (3, 3, 'three,three') 
     , (1, 1, 'one,one') 
     , (1, 2, '1,2'); 

Sur les 8 lignes, vous avez 5 impliqué des problèmes en double; 3 lignes doivent être enlevées. Vous pouvez voir les problèmes avec ceci:

SELECT col1 
    , col2 
    , col3 
    , COUNT(1) AS _total 
    FROM ##_dupes 
    WHERE 1=1 
    GROUP BY col1, col2, col3 
    HAVING COUNT(1) > 1 
    ORDER BY _total DESC; 

Maintenant, exécutez la requête suivante pour supprimer les doublons, en laissant 1 rang de chaque série de doublons.

WITH numbered AS (
    SELECT ROW_NUMBER() OVER(PARTITION BY col1, col2, col3 ORDER BY col1, col2, col3) AS _dupe_num FROM ##_dupes WHERE 1=1 
) 
DELETE FROM numbered WHERE _dupe_num > 1; 

Vous êtes maintenant à gauche avec 5 lignes, dont aucune n'est dupliquée.

+0

+1; pas la meilleure pratique, mais cela a résolu mon problème. – lyrisey

+0

+1: excellente explication de la syntaxe dans le ** résumé ** –

3

Même si u n'avez pas une clé primaire, u peut supprimer les données en double par le code ci-dessous

delete from (Tablename) 
      where tablename.%%physloc%% 
      NOT IN (select MIN(b.%%physloc%%) 
      from tablename b 
      group by b.Column1,b.column2,b.column3 
     ); 
+0

+1 mais vous devez mentionner la nature «non documentée» de l'installation 'physloc' - bien qu'il reste probablement là pour plusieurs versions, on ne sait jamais! –

Questions connexes