2012-03-20 5 views
1

J'ai une table avec 3 colonnes: id, date et name. Ce que je cherche est de supprimer les enregistrements qui ont un nom en double. La règle devrait être de conserver l'enregistrement qui a la date la plus ancienne. Par exemple dans l'exemple ci-dessous, il y a 3 enregistrements avec le nom Paul. Donc, je voudrais garder celui qui a la date la plus ancienne (id=1) et supprimer tous les autres (id = 4 and 6). Je sais comment faire des requêtes d'insertion, de mise à jour, etc., mais ici je ne vois pas comment faire pour que cela fonctionne.PHP SQL - requête de suppression avancée

id, date, name 

1, 2012-03-10, Paul 
2, 2012-03-10, James 
4, 2012-03-12, Paul 
5, 2012-03-11, Ricardo 
6, 2012-03-13, Paul 

mysql_query(?);

Répondre

1

La meilleure suggestion que je peux vous donner est créer un index unique sur name et éviter tous les problèmes.

Suivez les étapes Peter Kiss dit de 2 à 3. Procédez comme

ALTER Table tablename ADD UNIQUE INDEX name (name) 

Suivez ensuite 4 Insert everything from the temporary table to the original.

Toutes les nouvelles lignes en double, seront omis

+0

Bonjour Starx. Juste eu le temps de tester ce que vous proposez ce matin. Je l'aime parce que c'est simple. La chose est, lors de l'exécution d'une requête d'insertion, est-il un moyen de savoir si l'enregistrement n'a pas été inséré parce que la valeur existait déjà dans la table. J'ai essayé mysql_error, mais rien n'est récupéré dans ce cas ... – Marc

+0

@Marc, Vous pouvez vérifier mysql's [insérer en double] (http://dev.mysql.com/doc/refman/5.0/fr/insert-on- duplicate.html) – Starx

1
  1. Sélectionner tous les enregistrements que vous souhaitez conserver
  2. les insérer dans une table temporaire
  3. Supprimer tout de la table d'origine
  4. Insérez tout de la table temporaire à l'original
+0

Bonjour Peter? Merci pour la réponse. Que pensez-vous de la solution proposée par pritaeas? – Marc

+0

L'approche est bonne, la solution ne l'est pas. D'abord, vous devez créer une requête avec la clause ORDER BY et ensuite vous pouvez avoir une instruction SELECT avec GROUP BY: SELECT 'id' FROM (SELECT' id', 'nom' FROM 'table' ORDER BY' date') GROUP BY 'nom'. Dans ce cas, GROUP BY conservera les rangées les plus anciennes du jeu de résultats. –

1

Quelque chose comme ça marcherait:

DELETE FROM tablename WHERE id NOT IN (
    SELECT tablename.id FROM (
     SELECT MIN(date) as dateCol, name FROM tablename GROUP BY name /*select the minimum date and name, for each name*/ 
    ) as MyInnerQuery 
    INNER JOIN tablename on MyInnerQuery.dateCol = tablename.date 
     and MyInnerQuery.name = tablename.name /*select the id joined on the minimum date and the name*/ 
) /*Delete everything which isn't in the list of ids which are the minimum date fore each name*/ 
+0

Bonjour Matt. Merci. Il me faudra un peu de temps pour tester ça ... Je reviendrai – Marc

+0

Bonjour Matt. J'ai eu le temps de tester ça ce matin et ça ne marche malheureusement pas. Néanmoins, j'obtiens la logique de votre solution, mais ne comprenez pas pourquoi cela ne fonctionne pas ... – Marc

1

Comme Matt, mais sans se joindre à:

DELETE FROM `table` WHERE `id` NOT IN (
    SELECT `id` FROM (
     SELECT `id` FROM `table` GROUP BY `name` ORDER BY `date` 
    ) as A 
) 

Sans la première vous SELECT obtiendra "Vous ne pouvez pas spécifier la table cible 'table' pour la mise à jour dans la clause FROM"

+0

Bonjour pritaeas. Merci d'avoir essayé de m'aider. Que signifie le 'comme A'? – Marc

+0

@Marc A est un nom pour la requête interne –

+0

@pritaeas Sûrement que cela retournera tous les identifiants (Et donc supprimer aucun), vous avez besoin d'un top 1 ou similaire n'est-ce pas? –

0
DELETE t 
FROM tableX AS t 
    LEFT JOIN 
    (SELECT name 
      , MIN(date) AS first_date 
     FROM tableX 
     GROUP BY name 
    ) AS grp 
    ON grp.name = t.name 
    AND grp.first_date = t.date 
WHERE 
    grp.name IS NULL 
0
DELETE FROM thetable tt 
WHERE EXISTS (
    SELECT * 
    FROM thetable tx 
    WHERE tx.thename = tt.thename 
    AND tx.thedate > tt. thedate 
    ); 

(notez que "date" est un mot de réservataire (type) dans SQL, "et" nom est un mot réservé dans certaines implémentations SQL)