GROUP BY dans un UPDATE

Eléphant du PHP | 153 Messages

09 août 2007, 08:36

Bonjour,

Je souhaiterai faire une requête de ce genre :

Code : Tout sélectionner

UPDATE t1 SET x = x +1 GROUP BY y ORDER BY z ASC

Voici la structure de la table avec ses n-uplets :

Code : Tout sélectionner

CREATE TABLE `t1` ( `x` INT NOT NULL , `y` INT NOT NULL , `z` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ) ; INSERT INTO `t1` (`x`, `y`, `z`) VALUES (0, 1, 1); INSERT INTO `t1` (`x`, `y`, `z`) VALUES (0, 1, 2); INSERT INTO `t1` (`x`, `y`, `z`) VALUES (0, 1, 3); INSERT INTO `t1` (`x`, `y`, `z`) VALUES (0, 2, 4); INSERT INTO `t1` (`x`, `y`, `z`) VALUES (0, 2, 5); INSERT INTO `t1` (`x`, `y`, `z`) VALUES (0, 3, 6);
Le problème est que le GROUP BY semble être interdit dans un UPDATE.
Le but de cette requête est de modifier le 'x' pour chaque type 'y' ayant le 'z' minimum (je sais pas si c'est clair !).

Si vous avez une solution, je l'accueille avec grand plaisir :-)

Merci !

***

J'ai essayé de passer par les TABLE VIEW, ça ne fonctionne pas, je me suis ensuite lancé dans les TEMPORARY TABLE et là cela semble fonctionner (évidemment puisque du coup c'est une table différente...).

Code : Tout sélectionner

CREATE TEMPORARY TABLE t3 SELECT * FROM t1; UPDATE t1 SET x = x +1 WHERE t1.z IN ( SELECT t3.z FROM t3 GROUP BY t3.y ORDER BY t3.z ASC );
Mais si vous avez une solution qui ne nécessite pas de table temporaire, cela m'arrangerait :-)
http://gl2.delcedo.com/ Galaxialord 2 !

d0m
Mammouth du PHP | 1141 Messages

09 août 2007, 09:10

peut être avec une sous requete du genre:

Code : Tout sélectionner

UPDATE t1 SET x = x +1 WHERE z IN( SELECT MIN(z) FROM t1 GROUP BY y)

Eléphant du PHP | 153 Messages

09 août 2007, 10:36

Et ben non :-P

MySQL ne veut pas qu'on fasse de sous requêtes sur une table qu'on modifie...
#1093 - You can't specify target table 't1' for update in FROM clause
Ca aurait été trop facile :roll:

Merci quand même :-)

D'autres solutions ? :?
http://gl2.delcedo.com/ Galaxialord 2 !

d0m
Mammouth du PHP | 1141 Messages

09 août 2007, 10:49

MySQL ne veut pas qu'on fasse de sous requêtes sur une table qu'on modifie...
ok j'apprends ça

Alors je ne pense pas que c'est possible vu qu'il faut absolument faire une comparaison des z groupés par les y.

il te reste la solution des tables temporaires ou de 2 requetes distinctes.

ViPHP
ViPHP | 928 Messages

09 août 2007, 11:02

Normalement on peut faire des sous requêtes dans les UPDATE, ainsi que des jointures, mais ce n'est pas apparament possible de le faire sur les tables qu'on est en train de mettre à jour (ce qui est logique au fond).

Le mieux étant de passer par deux requêtes séparées.

Mammouth du PHP | 19672 Messages

09 août 2007, 15:39

Un petit tour dans la doc MySQL ne serait pas superflu non plus :-k

On y voit par exemple :
Syntaxe de UPDATE

Code : Tout sélectionner

UPDATE [LOW_PRIORITY] [IGNORE] tbl_name SET col_name1=expr1 [, col_name2=expr2 ...] [WHERE where_definition] [ORDER BY ...] [LIMIT row_count]
Syntaxe multi-tables :

Code : Tout sélectionner

UPDATE [LOW_PRIORITY] [IGNORE] tbl_name [, tbl_name ...] SET col_name1=expr1 [, col_name2=expr2 ...] [WHERE where_definition]
En clair, les clauses y sont très limitées, mais le WHERE est là : donc une sous-requête doit fonctionner. (MySQL >= 4.1)
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

d0m
Mammouth du PHP | 1141 Messages

09 août 2007, 15:53

Un petit tour dans la doc MySQL ne serait pas superflu non plus :-k
et une petite lecture attentive des messages ne le serait pas non plus :

Les sous requêtes sont acceptées tant qu'elles ne sont pas faites sur la table qu'on tente de modifier.

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

09 août 2007, 16:01

ça va, c'est pas un réglement de compte ... :roll:

J'avoue que j'ai du mal à comprendre pourquoi les sous-requêtes sont interdites :-k
Dans l'ordre d'exécution, quand l'UPDATE commence, la sous-requête est terminée ... donc pas de soucis de table mouvantes, normalement :?
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

09 août 2007, 18:17

Le but de cette requête est de modifier le 'x' pour chaque type 'y' ayant le 'z' minimum (je sais pas si c'est clair !).
A priori c'est très clair : pour chaque "y", trouve le "z" minimum, puis pour chaque enregistrement de "t1" correspondant aux valeurs de "y" et "z" incrémente "x".

Pour décomposer:
pour chaque "y", trouve le "z" minimum

Code : Tout sélectionner

SELECT y, MIN(z) AS z FROM t1 GROUP BY y
puis pour chaque enregistrement de "t1" correspondant aux valeurs de ("y", "z")

Code : Tout sélectionner

SELECT t1.* FROM t1 JOIN ( SELECT y, MIN(z) AS z FROM t1 GROUP BY y ) AS tmp USING (y, z)
[Note : USING (y, z) correspond à ON tmp.y = t1.y AND tmp.z = t1.z, c'est juste plus court et plus lisible]

incrémente "x"

Code : Tout sélectionner

UPDATE t1 JOIN ( SELECT y, MIN(z) AS z FROM t1 GROUP BY y ) AS tmp USING (y, z) SET t1.x = t1.x + 1
...et voilà qui devrait faire le travail.

Le "JOIN" avec la requête entre parenthèses est une table dérivée, c'est comme une table temporaire qui disparaît d'elle-même en fin de requête et ça permet de faire pas mal de truc, comme entre autres s'affranchir de la restriction dont vous parliez plus haut.

Eléphant du PHP | 153 Messages

12 août 2007, 11:06

Hey !

Merci beaucoup !!

La requête fonctionne parfaitement !

Je pensais que JOIN était aussi considéré comme une jointure par MySQL, enfin au même titre que la jointure "classique". Ben... non :-P. Je me coucherai moins bête.

Je crois que cette solution va m'être bien utile pour la suite, encore merci !

En tout cas je tiens vous remercier tous pour s'être penchés sur mon problème.

Merci !
http://gl2.delcedo.com/ Galaxialord 2 !