Je sais que vous pouvez insérer plusieurs lignes à la fois, existe-t-il un moyen de mettre à jour plusieurs lignes à la fois (comme dans, dans une seule requête) dans MySQL?
Edit: Par exemple, j'ai les éléments suivants
Name id Col1 Col2
Row1 1 6 1
Row2 2 2 3
Row3 3 9 5
Row4 4 16 8
Je souhaite combiner toutes les mises à jour suivantes en une seule requête
UPDATE table SET Col1 = 1 WHERE id = 1;
UPDATE table SET Col1 = 2 WHERE id = 2;
UPDATE table SET Col2 = 3 WHERE id = 3;
UPDATE table SET Col1 = 10 WHERE id = 4;
UPDATE table SET Col2 = 12 WHERE id = 4;
mysql
sql
sql-update
Teifion
la source
la source
Étant donné que vous avez des valeurs dynamiques, vous devez utiliser un IF ou CASE pour les colonnes à mettre à jour. Ça devient un peu moche, mais ça devrait marcher.
En utilisant votre exemple, vous pouvez le faire comme:
la source
$commandTxt = 'UPDATE operations SET chunk_finished = CASE id '; foreach ($blockOperationChecked as $operationID => $operationChecked) $commandTxt .= " WHEN $operationID THEN $operationChecked "; $commandTxt .= 'ELSE id END WHERE id IN ('.implode(', ', array_keys(blockOperationChecked )).');';
La question est ancienne, mais j'aimerais étendre le sujet avec une autre réponse.
Mon point est que la façon la plus simple d'y parvenir est simplement d'envelopper plusieurs requêtes avec une transaction. La réponse acceptée
INSERT ... ON DUPLICATE KEY UPDATE
est un joli hack, mais il faut être conscient de ses inconvénients et limites:"Field 'fieldname' doesn't have a default value"
avertissement MySQL même si vous n'insérez pas une seule ligne du tout. Cela vous posera des problèmes si vous décidez d'être strict et de transformer les avertissements mysql en exceptions d'exécution dans votre application.J'ai fait quelques tests de performance pour trois des variantes suggérées, y compris la
INSERT ... ON DUPLICATE KEY UPDATE
variante, une variante avec la clause "case / when / then" et une approche naïve avec la transaction. Vous pouvez obtenir le code python et les résultats ici . La conclusion générale est que la variante avec l'instruction case s'avère deux fois plus rapide que deux autres variantes, mais il est assez difficile d'écrire un code correct et sûr pour l'injection, donc je persiste personnellement à l'approche la plus simple: utiliser les transactions.Edit: Les résultats de Dakusan prouvent que mes estimations de performances ne sont pas tout à fait valides. Veuillez consulter cette réponse pour une autre recherche plus élaborée.
la source
Je ne sais pas pourquoi une autre option utile n'est pas encore mentionnée:
la source
Tout ce qui suit s'applique à InnoDB.
Je pense que connaître les vitesses des 3 méthodes différentes est important.
Il existe 3 méthodes:
Je viens de tester cela, et la méthode INSERT était de 6,7x plus rapide pour moi que la méthode TRANSACTION. J'ai essayé sur un ensemble de 3 000 et 30 000 lignes.
La méthode TRANSACTION doit toujours exécuter chaque requête individuellement, ce qui prend du temps, bien qu'elle traite les résultats en mémoire, ou quelque chose, lors de l'exécution. La méthode TRANSACTION est également assez coûteuse dans les journaux de réplication et de requête.
Pire encore, la méthode CASE était 41,1 fois plus lente que la méthode INSERT avec 30 000 enregistrements (6,1 fois plus lente que TRANSACTION). Et 75 fois plus lent dans MyISAM. Les méthodes INSERT et CASE ont même atteint environ 1 000 enregistrements. Même à 100 enregistrements, la méthode CASE est À peine plus rapide.
Donc, en général, je pense que la méthode INSERT est à la fois la meilleure et la plus facile à utiliser. Les requêtes sont plus petites et plus faciles à lire et ne prennent qu'une seule requête d'action. Cela s'applique à la fois à InnoDB et à MyISAM.
Trucs bonus:
La solution pour le problème INSERT non-champ par défaut est de désactiver temporairement les modes SQL pertinents:
SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES","")
. Assurez-vous d'enregistrer lesql_mode
premier si vous prévoyez de le rétablir.Quant aux autres commentaires que j'ai vus qui disent que l'auto_increment monte en utilisant la méthode INSERT, cela semble être le cas dans InnoDB, mais pas MyISAM.
Le code pour exécuter les tests est le suivant. Il génère également des fichiers .SQL pour supprimer la surcharge de l'interpréteur php
la source
Utiliser une table temporaire
la source
Cela devrait fonctionner pour toi.
Il y a une référence dans le manuel MySQL pour plusieurs tables.
la source
Pourquoi personne ne mentionne-t-il plusieurs déclarations dans une même requête ?
En php, vous utilisez la
multi_query
méthode de l'instance mysqli.Depuis le manuel php
Voici le résultat par rapport aux 3 autres méthodes de la mise à jour 30 000 raw. Le code peut être trouvé ici, basé sur la réponse de @Dakusan
Transaction: 5,5194580554962
Insert: 0,20669293403625
Caisse: 16,474853992462
Multi: 0,0412278175354
Comme vous pouvez le voir, la requête à plusieurs déclarations est plus efficace que la réponse la plus élevée.
Si vous obtenez un message d'erreur comme celui-ci:
Vous devrez peut-être augmenter le
max_allowed_packet
fichier de configuration dans mysql qui se trouve sur ma machine/etc/mysql/my.cnf
, puis redémarrer mysqld.la source
$mysqli->multi_query($sql)
pris "0" secondes. Cependant, les requêtes suivantes ont échoué, ce qui m'a obligé à en faire un "programme" distinct.Il existe un paramètre que vous pouvez modifier appelé «instruction multiple» qui désactive le «mécanisme de sécurité» de MySQL implémenté pour empêcher (plus d'une) commande d'injection. Typique de l'implémentation «brillante» de MySQL, elle empêche également l'utilisateur d'effectuer des requêtes efficaces.
Voici ( http://dev.mysql.com/doc/refman/5.1/en/mysql-set-server-option.html ) quelques informations sur l'implémentation C du paramètre.
Si vous utilisez PHP, vous pouvez utiliser mysqli pour faire plusieurs instructions (je pense que php est livré avec mysqli depuis un certain temps maintenant)
J'espère que cela pourra aider.
la source
mysqli::begin_transaction(..)
avant d'envoyer la requête etmysql::commit(..)
après. Ou utilisezSTART TRANSACTION
comme première etCOMMIT
dernière instruction dans la requête elle-même.Vous pouvez alias la même table pour vous donner les identifiants que vous souhaitez insérer (si vous effectuez une mise à jour ligne par ligne:
De plus, il devrait sembler évident que vous pouvez également mettre à jour à partir d'autres tables. Dans ce cas, la mise à jour se double d'une instruction "SELECT", vous donnant les données de la table que vous spécifiez. Vous indiquez explicitement dans votre requête les valeurs de mise à jour, la deuxième table n'est donc pas affectée.
la source
Vous pouvez également être intéressé par l'utilisation de jointures sur les mises à jour, ce qui est également possible.
Modifier: si les valeurs que vous mettez à jour ne proviennent pas d'un autre endroit de la base de données, vous devrez émettre plusieurs requêtes de mise à jour.
la source
Et maintenant, le moyen le plus simple
la source
utilisation
Notez s'il vous plaît:
la source
Les éléments suivants mettront à jour toutes les lignes d'une même table
Le suivant mettra à jour toutes les lignes où la valeur de Column2 est supérieure à 5
Il existe tous les exemples d' Unkwntech de mise à jour de plusieurs tables
la source
Oui .. c'est possible en utilisant l'instruction SQL INSERT ON DUPLICATE KEY UPDATE .. syntaxe: INSERT INTO nom_table (a, b, c) VALEURS (1,2,3), (4,5,6) ON DUPLICATE KEY UPDATE a = VALEURS (a), b = VALEURS (b), c = VALEURS (c)
la source
Cela devrait atteindre ce que vous recherchez. Ajoutez simplement plus d'identifiants. Je l'ai testé.
la source
// Vous venez de le construire en php comme
Vous pouvez donc mettre à jour la table de trous avec une seule requête
la source
something
àsomething
)