web-dev-qa-db-fra.com

Comment puis-je supprimer l'une des deux lignes parfaitement identiques?

Je nettoie une table de base de données sans clé primaire (je sais, je sais, à quoi pensaient-ils?). Je ne peux pas ajouter de clé primaire car il y a un doublon dans la colonne qui deviendrait la clé. La valeur en double provient de l'une des deux lignes qui sont identiques à tous égards. Je ne peux pas supprimer la ligne via une interface graphique (dans ce cas, MySQL Workbench, mais je recherche une approche agnostique de la base de données) car elle refuse d'effectuer des tâches sur des tables sans clé primaire (ou au moins une colonne UQ NN) Je ne peux pas ajouter de clé primaire car il y a un doublon dans la colonne qui deviendrait la clé. La valeur en double provient d'un ...

Comment puis-je supprimer l'un des jumeaux?

27
d3vid

Une option pour résoudre votre problème consiste à créer une nouvelle table avec le même schéma, puis procédez comme suit:

INSERT INTO new_table (SELECT DISTINCT * FROM old_table)

et puis il suffit de renommer les tables.

Pour ce faire, vous aurez bien sûr besoin de la même quantité d’espace que votre table a besoin d’espace libre!

Ce n'est pas efficace, mais c'est incroyablement simple.

19
Alnitak
SET ROWCOUNT 1
DELETE FROM [table] WHERE ....
SET ROWCOUNT 0

Cela ne supprimera qu'une des deux lignes identiques

51
Rinaldo

Notez que MySQL a sa propre extension de DELETE, qui est DELETE ... LIMIT, qui fonctionne comme vous le souhaiteriez de LIMIT: http://dev.mysql.com/doc/refman/5.0/en/delete.html

L'option LIMIT row_count spécifique à MySQL pour DELETE indique au serveur le nombre maximal de lignes à supprimer avant que le contrôle soit renvoyé à le client. Ceci peut être utilisé pour s'assurer qu'une instruction DELETE donnée ne prend pas trop de temps. Vous pouvez simplement répéter le message DELETE instruction jusqu'à ce que le nombre de lignes affectées soit inférieur à LIMIT valeur.

Par conséquent, vous pouvez utiliser DELETE FROM some_table WHERE x="y" AND foo="bar" LIMIT 1; et notez qu'il n'existe pas de moyen simple de dire "tout supprimer sauf un" - il suffit de vérifier si vous avez toujours des doublons de lignes.

19
Piskvor

Pour PostgreSQL, vous pouvez faire ceci:

DELETE FROM tablename
WHERE id IN (SELECT id
          FROM (SELECT id, ROW_NUMBER() 
               OVER (partition BY column1, column2, column3 ORDER BY id) AS rnum
               FROM tablename) t
          WHERE t.rnum > 1);

column1, column2, column3 serait l'ensemble de colonnes contenant des valeurs dupliquées.

Référence ici .

10
Turbut Alin

delete top (1) fonctionne sur Microsoft SQL Server (T-SQL).

5
mattinsalto

Ceci peut être accompli en utilisant un CTE et la fonction ROW_NUMBER(), comme ci-dessous:

/* Sample Data */
    CREATE TABLE #dupes (ID INT, DWCreated DATETIME2(3))

    INSERT INTO #dupes (ID, DWCreated) SELECT 1, '2015-08-03 01:02:03.456'
    INSERT INTO #dupes (ID, DWCreated) SELECT 2, '2014-08-03 01:02:03.456'
    INSERT INTO #dupes (ID, DWCreated) SELECT 1, '2013-08-03 01:02:03.456'

/* Check sample data - returns three rows, with two rows for ID#1 */
    SELECT * FROM #dupes 

/* CTE to give each row that shares an ID a unique number */
    ;WITH toDelete AS
      (
        SELECT ID, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY DWCreated) AS RN
        FROM #dupes 
      )

  /* Delete any row that is not the first instance of an ID */
    DELETE FROM toDelete WHERE RN > 1

/* Check the results: ID is now unique */
    SELECT * FROM #dupes

/* Clean up */
    DROP TABLE #dupes

Avoir une colonne à ORDER BY est pratique, mais pas nécessaire sauf si vous avez une préférence pour laquelle des lignes à supprimer. Cela traitera également toutes les occurrences d’enregistrements en double, au lieu de vous obliger à supprimer une ligne à la fois. 

4
AHiggins

Essayé Limite 1? Cela ne supprimera que 1 des lignes correspondant à votre requête DELETE

DELETE FROM `table_name` WHERE `column_name`='value' LIMIT 1;
3
Feelsbadman

Dans mon cas, je pourrais demander à l'interface graphique de me donner une chaîne de valeurs de la ligne en question (sinon, j'aurais pu le faire à la main). Sur la suggestion d'un collègue, à qui je reste redevable, j'ai utilisé cette information pour créer une instruction INSERT:

INSERT
'ID1219243408800307444663', '2004-01-20 10:20:55', 'INFORMATION', 'admin' (...)
INTO some_table;

J'ai testé la déclaration insert, de sorte que j'avais maintenant des triplets. Enfin, j'ai exécuté un simple DELETE pour tous les supprimer ...

DELETE FROM some_table WHERE logid = 'ID1219243408800307444663';

suivi de l'INSERT une fois de plus, me laissant avec une seule ligne et les possibilités lumineuses d'une clé primaire.

1
d3vid

au cas où vous pouvez ajouter une colonne comme

  ALTER TABLE yourtable ADD IDCOLUMN bigint NOT NULL IDENTITY (1, 1)

fais le.

puis comptez les rangées de groupes en fonction de la colonne de votre problème où compte> 1, ceci identifiera vos jumeaux (ou triplés ou autre).

puis sélectionnez la colonne de votre problème où son contenu est égal au contenu identifié ci-dessus et vérifiez les ID dans IDCOLUMN. 

supprimer de votre table où IDCOLUMN est égal à l'un de ces ID.

1
Der U

Cela fonctionne pour PostgreSQL

DELETE FROM tablename WHERE id = 123 AND ctid IN (SELECT ctid FROM tablename WHERE id = 123 LIMIT 1)
1
Vlad B

Vous pouvez utiliser un max, ce qui était pertinent dans mon cas.

DELETE FROM [table] where id in 
(select max(id) from [table] group by id, col2, col3 having count(id) > 1)

Assurez-vous de tester vos résultats en premier et d'avoir une condition limitante dans votre "avoir" clausule. Avec une telle requête de suppression, vous voudrez peut-être mettre à jour votre base de données en premier.

1
TIm

Dans PostgreSQL, il existe une colonne implicite appelée ctid. Voir le wiki . Vous êtes donc libre d'utiliser les éléments suivants:

WITH cte1 as(
    SELECT unique_column, max( ctid ) as max_ctid
    FROM table_1
    GROUP BY unique_column
    HAVING count(*) > 1
), cte2 as(
    SELECT t.ctid as target_ctid
    FROM table_1 t
    JOIN cte1 USING( unique_column )
    WHERE t.ctid != max_ctid
)
DELETE FROM table_1
WHERE ctid IN( SELECT target_ctid FROM cte2 )

Je ne sais pas dans quelle mesure il est sécuritaire de l'utiliser lorsque des mises à jour simultanées sont possibles. Il est donc judicieux de créer un LOCK TABLE table_1 IN ACCESS EXCLUSIVE MODE; avant de procéder au nettoyage.

0
volvpavl

J'ai ajouté une colonne Guid à la table et l'ai configurée pour générer un nouvel identifiant pour chaque ligne. Ensuite, je pourrais supprimer les lignes en utilisant une interface graphique.

0
Ian Warburton