par
Hywan » 17 mai 2008, 16:15
Bon voici mes tests, mais je bloque.
On commence par faire notre table de test, et on y insère nos données :
Code : Tout sélectionner
CREATE TABLE IF NOT EXISTS `ma_table` (
`id` int(11) NOT NULL auto_increment COMMENT 'Identifiant.',
`champ` varchar(255) NOT NULL COMMENT 'Champ au pif.',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;
INSERT INTO `ma_table` (`id`, `champ`) VALUES
(1, 'a'),
(2, 'b'),
(3, 'c'),
(4, 'd'),
(5, 'e'),
(6, 'f'),
(7, 'a'),
(8, 'd'),
(9, 'a');
Voici mes tests :
Code : Tout sélectionner
mysql> SHOW TABLES;
+----------------+
| Tables_in_test |
+----------------+
| ma_table |
+----------------+
1 row in set (0.00 sec)
J'ai tout d'abord sélectionner tous les champs avec leur nombre d'apparition. On doit voir apparaître a et d qui apparaissent respectivement 3 et 2. C'est facile, mais c'est pas intéressant. Ce qu'on veut, c'est avoir tous les a et les d listés avec leur id. On aurait alors :
Code : Tout sélectionner
mysql> SELECT a.id, a.champ
-> FROM ma_table AS a,
-> (SELECT champ, COUNT(champ)
-> FROM ma_table
-> GROUP BY champ
-> HAVING COUNT(champ) > 1) AS b
-> WHERE a.champ = b.champ;
+----+-------+
| id | champ |
+----+-------+
| 1 | a |
| 4 | d |
| 7 | a |
| 8 | d |
| 9 | a |
+----+-------+
5 rows in set (0.00 sec)
C'est pas très optimisé. J'ai amélioré la charge mémoire en faisant :
Code : Tout sélectionner
mysql> SELECT DISTINCT *
-> FROM ma_table AS a
-> WHERE EXISTS (SELECT *
-> FROM ma_table AS b
-> WHERE a.id <> b.id
-> AND a.champ = b.champ);
+----+-------+
| id | champ |
+----+-------+
| 1 | a |
| 4 | d |
| 7 | a |
| 8 | d |
| 9 | a |
+----+-------+
5 rows in set (0.00 sec)
Bien, on a les champs, mais c'est pas encore ce qu'on veut exactement. Quand on a plusieurs fois la même valeur, on veut en conserver une. J'ai pris le choix de conserver la dernière entrée et pas la première. On aurait alors :
Code : Tout sélectionner
mysql> SELECT id, champ
-> FROM ma_table AS a
-> WHERE a.id < ANY (SELECT id
-> FROM ma_table AS b
-> WHERE a.id <> b.id
-> AND a.champ = b.champ);
+----+-------+
| id | champ |
+----+-------+
| 1 | a |
| 4 | d |
| 7 | a |
+----+-------+
3 rows in set (0.00 sec)
Bien, c'est ça.
Maintenant, il faut supprimer. J'ai essayé 10 façons différentes, j'ai toujours la même erreur. J'ai essayé avec ou sans ANY, avec des EXISTS, des IN, des divisions etc., j'ai toujours une erreur avec le DELETE. Alors bon, je vous soumets ce que j'ai fais, si quelqu'un peut aller plus loin, ce sera bien

.
On peut le faire sinon en modifiant la table : soit en modifie les valeurs de champ, soit on crée un nouvel attribut. Mais j'aime pas trop cette méthode, je ne l'ai pas exploré plus que ça.
Sinon, on peut le faire en plusieurs requêtes. On aurait quelque chose du genre :
Code : Tout sélectionner
CREATE TABLE temp_table
FROM (SELECT id, champ
FROM ma_table
GROUP BY champ);
DELETE FROM ma_table;
INSERT INTO ma_table
SELECT * FROM temp_table;
COMMIT;
DROP TABLE temp_table; Mais j'ai pas testé ce code. J'ai surtout essayé de le faire en une seule fois …
Wala Monsieur, en espérant que ça avancer un peu les choses.
Bon voici mes tests, mais je bloque.
On commence par faire notre table de test, et on y insère nos données : [code]CREATE TABLE IF NOT EXISTS `ma_table` (
`id` int(11) NOT NULL auto_increment COMMENT 'Identifiant.',
`champ` varchar(255) NOT NULL COMMENT 'Champ au pif.',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;
INSERT INTO `ma_table` (`id`, `champ`) VALUES
(1, 'a'),
(2, 'b'),
(3, 'c'),
(4, 'd'),
(5, 'e'),
(6, 'f'),
(7, 'a'),
(8, 'd'),
(9, 'a');[/code]
Voici mes tests : [code]mysql> SHOW TABLES;
+----------------+
| Tables_in_test |
+----------------+
| ma_table |
+----------------+
1 row in set (0.00 sec)[/code]
J'ai tout d'abord sélectionner tous les champs avec leur nombre d'apparition. On doit voir apparaître a et d qui apparaissent respectivement 3 et 2. C'est facile, mais c'est pas intéressant. Ce qu'on veut, c'est avoir tous les a et les d listés avec leur id. On aurait alors : [code]mysql> SELECT a.id, a.champ
-> FROM ma_table AS a,
-> (SELECT champ, COUNT(champ)
-> FROM ma_table
-> GROUP BY champ
-> HAVING COUNT(champ) > 1) AS b
-> WHERE a.champ = b.champ;
+----+-------+
| id | champ |
+----+-------+
| 1 | a |
| 4 | d |
| 7 | a |
| 8 | d |
| 9 | a |
+----+-------+
5 rows in set (0.00 sec)[/code]
C'est pas très optimisé. J'ai amélioré la charge mémoire en faisant : [code]mysql> SELECT DISTINCT *
-> FROM ma_table AS a
-> WHERE EXISTS (SELECT *
-> FROM ma_table AS b
-> WHERE a.id <> b.id
-> AND a.champ = b.champ);
+----+-------+
| id | champ |
+----+-------+
| 1 | a |
| 4 | d |
| 7 | a |
| 8 | d |
| 9 | a |
+----+-------+
5 rows in set (0.00 sec)[/code]
Bien, on a les champs, mais c'est pas encore ce qu'on veut exactement. Quand on a plusieurs fois la même valeur, on veut en conserver une. J'ai pris le choix de conserver la dernière entrée et pas la première. On aurait alors : [code]mysql> SELECT id, champ
-> FROM ma_table AS a
-> WHERE a.id < ANY (SELECT id
-> FROM ma_table AS b
-> WHERE a.id <> b.id
-> AND a.champ = b.champ);
+----+-------+
| id | champ |
+----+-------+
| 1 | a |
| 4 | d |
| 7 | a |
+----+-------+
3 rows in set (0.00 sec)[/code]
Bien, c'est ça.
Maintenant, il faut supprimer. J'ai essayé 10 façons différentes, j'ai toujours la même erreur. J'ai essayé avec ou sans ANY, avec des EXISTS, des IN, des divisions etc., j'ai toujours une erreur avec le DELETE. Alors bon, je vous soumets ce que j'ai fais, si quelqu'un peut aller plus loin, ce sera bien :).
On peut le faire sinon en modifiant la table : soit en modifie les valeurs de champ, soit on crée un nouvel attribut. Mais j'aime pas trop cette méthode, je ne l'ai pas exploré plus que ça.
Sinon, on peut le faire en plusieurs requêtes. On aurait quelque chose du genre : [code]CREATE TABLE temp_table
FROM (SELECT id, champ
FROM ma_table
GROUP BY champ);
DELETE FROM ma_table;
INSERT INTO ma_table
SELECT * FROM temp_table;
COMMIT;
DROP TABLE temp_table;[/code] Mais j'ai pas testé ce code. J'ai surtout essayé de le faire en une seule fois …
Wala Monsieur, en espérant que ça avancer un peu les choses.