98 votes

Mise à jour MySQL CASE WHEN/THEN/ELSE

J'essaie de mettre à jour une GRANDE table MyISAM (25 millions d'enregistrements) en utilisant un CLI script. La table n'est pas verrouillée/utilisée par autre chose.

Je me suis dit qu'au lieu d'effectuer des requêtes UPDATE uniques pour chaque enregistrement, je pourrais tout aussi bien utiliser la fonction CASE.

En id est PRIMAIRE. Je pense que la requête suivante devrait prendre quelques millisecondes.

UPDATE `table` SET `uid` = CASE
    WHEN id = 1 THEN 2952
    WHEN id = 2 THEN 4925
    WHEN id = 3 THEN 1592
    END

Et voilà que la requête monopolise le processeur et ne se termine pas avant une éternité.

Puis, à ma grande surprise, j'ai découvert que la requête mettait à jour les 25 millions de lignes, en plaçant un NULL sur les lignes que je n'avais pas spécifiées.

A quoi cela sert-il ? Puis-je simplement faire une mise à jour en masse sur des lignes spécifiques sans mettre à jour 25 millions de lignes à chaque fois que j'exécute cette requête ? Ou dois-je effectuer des mises à jour individuelles, puis effectuer un commit ?

197voto

rs. Points 11670

Essayez ceci

UPDATE `table` SET `uid` = CASE
    WHEN id = 1 THEN 2952
    WHEN id = 2 THEN 4925
    WHEN id = 3 THEN 1592
    ELSE `uid`
    END
WHERE id  in (1,2,3)

8voto

Ross Smith II Points 4839

Si id est séquentiel en commençant par 1, le plus simple (et le plus rapide) serait :

UPDATE `table` 
SET uid = ELT(id, 2952, 4925, 1592) 
WHERE id IN (1,2,3)

Comme PELT() retourne le Nième élément de la liste de chaînes de caractères : str1 si N = 1, str2 si N = 2, et ainsi de suite. Renvoie NULL si N est inférieur à 1 ou supérieur au nombre d'arguments.

Il est clair que le code ci-dessus ne fonctionne que si id est 1, 2 ou 3. Si id était de 10, 20 ou 30, l'une ou l'autre des solutions suivantes fonctionnerait :

UPDATE `table` 
SET uid = CASE id 
WHEN 10 THEN 2952 
WHEN 20 THEN 4925 
WHEN 30 THEN 1592 END CASE 
WHERE id IN (10, 20, 30)

ou le plus simple :

UPDATE `table` 
SET uid = ELT(FIELD(id, 10, 20, 30), 2952, 4925, 1592) 
WHERE id IN (10, 20, 30)

Comme FIELD() renvoie l'index (position) de str dans la liste str1, str2, str3, .... Retourne 0 si str n'est pas trouvé.

5voto

alex Points 3316

C'est parce que tu as manqué ELSE.

"Renvoie le résultat de la première condition qui est vraie. S'il n'y avait pas de valeur de résultat correspondante, le résultat après ELSE est renvoyé, ou NULL s'il n'y a pas de partie ELSE." ( http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html#operator_case )

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X