2017-03-11 6 views
3

Dire que j'ai les deux tables players et stats avec le contenu suivant:Accès à une colonne précédemment mis à jour dans la même requête se comporte différemment avec JOIN/updates multi-tables

mysql> select * from players; 
+----+-------+ 
| id | alive | 
+----+-------+ 
| 1 |  0 | 
| 2 |  1 | 
+----+-------+ 
mysql> select * from stats; 
+--------+------+------+-------+ 
| player | win | lose | ratio | 
+--------+------+------+-------+ 
|  1 | 12 | 20 | 0.6 | 
|  2 | 8 | 1 |  8 | 
+--------+------+------+-------+ 

Et je veux incrémenter win -counter de chaque joueur, tout en mettant à jour leur rapport gagnant/perdant. Cela ressemblerait à quelque chose comme ceci:

update `stats` set `win` = `win` + 1, `ratio` = `win`/`lose`; 

Notez que la valeur incrémentée de win est utilisée pour calculer la ratio (comme les états manuels de MySQL ici: 1.8.2.2 UPDATE Differences).

Maintenant, lorsqu'un JOIN est ajouté à l'UPDATE requête de le limiter aux joueurs que de mise à jour où alive = 1, ce comportement change:

update `stats` st 
inner join `players` pl 
    on (pl.`id` = st.`player`) 
set `win` = `win` + 1, `ratio` = `win`/`lose` 
where pl.`alive` = 1; 

mysql> select * from stats; 
+--------+------+------+-------+ 
| player | win | lose | ratio | 
+--------+------+------+-------+ 
|  1 | 12 | 20 | 0.6 | 
|  2 | 9 | 1 |  8 | 
+--------+------+------+-------+ 

La seule solution que j'ai trouvé est d'attribuer la nouvelle valeur de win à une variable temporaire et utiliser celui-ci lors du calcul du ratio à la place:

update `stats` st 
inner join `players` pl 
    on (pl.`id` = st.`player`) 
set 
    `win` = @tmpWin := (`win` + 1), 
    `ratio` = @tmpWin/`lose` 
where pl.`alive` = 1; 

Pourquoi MySQL se comporte comme ça, et est-il une solution plus élégante à un probl em de ce genre (autre que de créer une vue pour calculer le ratio à la volée)?

Les tableaux ont été créés comme suit:

create table `players` (
    `id`  INT, 
    `alive`  TINYINT, 
    primary key (`id`) 
); 

create table `stats` (
    `player` INT, 
    `win`  INT, 
    `lose`  INT, 
    `ratio`  FLOAT, 
    primary key (`player`) 
); 

J'utilise MySQL v5.7.17

+0

Avec 5.7.17, vous pouvez utiliser [colonnes générées] (https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html). –

Répondre

1

Je ne peux pas expliquer le comportement de la jointure affaire qui semble bien étrange, mais les œuvres suivantes prévu:

UPDATE `stats` 
SET `win` = `win` + 1, `ratio` = `win`/`lose` 
WHERE player IN (SELECT id FROM players WHERE alive=1);