MySQL, mettez à jour plusieurs tables avec une seule requête

132

J'ai une fonction qui met à jour trois tables, mais j'utilise trois requêtes pour effectuer cela. Je souhaite utiliser une approche plus pratique pour les bonnes pratiques.

Comment puis-je mettre à jour plusieurs tables dans MySQL avec une seule requête?

Adamski
la source
3
pouvez-vous fournir un exemple du code généré? Y a-t-il une clé commune entre les tables?
Jonathan Day

Réponses:

451

Prenons le cas de deux tables, Bookset Orders. Dans le cas où nous augmentons le nombre de livres dans un ordre particulier avec Order.ID = 1002dans le Orderstableau, nous devons également réduire le nombre total de livres disponibles dans notre stock du même nombre dans le Bookstableau.

UPDATE Books, Orders
SET Orders.Quantity = Orders.Quantity + 2,
    Books.InStock = Books.InStock - 2
WHERE
    Books.BookID = Orders.BookID
    AND Orders.OrderID = 1002;
Irfan
la source
Si je veux inclure "LIMIT" dans la requête SQL, dois-je dire LIMIT 1 ou LIMIT 2?
Bluedayz
2
Quel est l'avantage de faire cela par rapport à une transaction? Merci!
paulkon
2
@paulkon, je suppose que lors de l'utilisation de transactions, il y a beaucoup de frais généraux impliqués car les annulations doivent être disponibles si une procédure de la transaction échoue.
Thijs Riezebeek
27
Avertissement général lors de l'utilisation de cette requête. La clause WHERE est évaluée séparément pour chaque table. Le Books.BookID = Orders.BookID est très important, sans lui La mise à jour de la table Books se produirait à toutes les lignes et pas seulement à la ligne avec l'ID spécifié. Certaines leçons sont apprises à la dure, celle-ci a été apprise de manière terrifiante.
nheimann1
1
@ nheimann1 Et c'est exactement pourquoi je recommande toujours aux gens d'utiliser la syntaxe ANSI "inner join". Il est trop facile d'oublier cette condition et d'obtenir à la place une jointure cartésienne complète.
fool4jesus
77
UPDATE t1
INNER JOIN t2 ON t2.t1_id = t1.id
INNER JOIN t3 ON t2.t3_id = t3.id
SET t1.a = 'something',
    t2.b = 42,
    t3.c = t2.c
WHERE t1.a = 'blah';

Pour voir ce que cela va mettre à jour, vous pouvez le convertir en une instruction de sélection, par exemple:

SELECT t2.t1_id, t2.t3_id, t1.a, t2.b, t2.c AS t2_c, t3.c AS t3_c
FROM t1
INNER JOIN t2 ON t2.t1_id = t1.id
INNER JOIN t3 ON t2.t3_id = t3.id
WHERE t1.a = 'blah';

Un exemple utilisant les mêmes tableaux que l'autre réponse:

SELECT Books.BookID, Orders.OrderID,
    Orders.Quantity AS CurrentQuantity,
    Orders.Quantity + 2 AS NewQuantity,
    Books.InStock AS CurrentStock,
    Books.InStock - 2 AS NewStock
FROM Books
INNER JOIN Orders ON Books.BookID = Orders.BookID
WHERE Orders.OrderID = 1002;

UPDATE Books
INNER JOIN Orders ON Books.BookID = Orders.BookID
SET Orders.Quantity = Orders.Quantity + 2,
    Books.InStock = Books.InStock - 2
WHERE Orders.OrderID = 1002;

ÉDITER:

Juste pour le plaisir, ajoutons quelque chose d'un peu plus intéressant.

Disons que vous avez une table de bookset une table de authors. Vous booksavez un author_id. Mais lorsque la base de données a été créée à l'origine, aucune contrainte de clé étrangère n'a été définie et plus tard, un bogue dans le code frontal a provoqué l'ajout de certains livres avec des author_ids invalides . En tant que DBA, vous ne voulez pas avoir à parcourir tous ces éléments bookspour vérifier ce que author_iddevrait être, donc la décision est prise que les capteurs de données corrigent le bookspoint à droite authors. Mais il y a trop de livres pour parcourir chacun d'eux et disons que vous savez que ceux qui ont un author_idqui correspond à un réel authorsont corrects. Ce sont juste ceux qui n'ont pasauthor_ids qui ne sont pas valides. Il existe déjà une interface permettant aux utilisateurs de mettre à jour les détails du livre et les développeurs ne veulent pas changer cela uniquement pour ce problème. Mais l'interface existante fait un INNER JOIN authors, donc tous les livres dont les auteurs sont invalides sont exclus.

Voici ce que vous pouvez faire: Insérez un faux enregistrement d'auteur comme "Auteur inconnu". Mettez ensuite à jour le author_idde tous les mauvais enregistrements pour pointer vers l'auteur inconnu. Ensuite, les captureurs de données peuvent rechercher tous les livres dont l'auteur est défini sur "Auteur inconnu", rechercher l'auteur correct et les corriger.

Comment mettre à jour tous les mauvais enregistrements pour qu'ils pointent vers l'auteur inconnu? Comme ceci (en supposant que l'auteur inconnu author_idest 99999):

UPDATE books
LEFT OUTER JOIN authors ON books.author_id = authors.id
SET books.author_id = 99999
WHERE authors.id IS NULL;

Ce qui précède mettra également à jour booksqui ont un NULL author_idauteur inconnu. Si vous ne le souhaitez pas, vous pouvez bien sûr ajouter AND books.author_id IS NOT NULL.

Wodin
la source
35

Vous pouvez également le faire avec une requête en utilisant une jointure comme ceci:

UPDATE table1,table2 SET table1.col=a,table2.col2=b
WHERE items.id=month.id;

Et puis envoyez simplement cette requête, bien sûr. Vous pouvez en savoir plus sur les jointures ici: http://dev.mysql.com/doc/refman/5.0/en/join.html . Il y a aussi quelques restrictions pour commander et limiter les mises à jour de plusieurs tables que vous pouvez lire ici: http://dev.mysql.com/doc/refman/5.0/en/update.html (juste ctrl + f "join").

Stephen Searles
la source
C'est un peu généreux d'appeler ça une "jointure" ;-)
underscore_d
2

C'est généralement à cela que servent les procédures stockées: implémenter plusieurs instructions SQL dans une séquence. En utilisant les annulations, vous pouvez vous assurer qu'elles sont traitées comme une seule unité de travail, c'est-à-dire qu'elles sont toutes exécutées ou qu'aucune d'entre elles ne l'est, pour que les données restent cohérentes.

SteveCav
la source
où écrirais-je la procédure? pouvez-vous donner un exemple?
Adamski
1
Voté pour expliquer la nécessité de l'atomicité - il est également important de réaliser que l'utilisation de procédures stockées ne garantit pas à elle seule la cohérence, vous devez toujours utiliser des transactions; de même, les transactions peuvent être effectuées sans utiliser de procédure stockée, à condition qu'elles soient effectuées via la même connexion. Dans ce cas, l'utilisation d'une mise à jour multi-tables est encore meilleure.
Duncan le
2

Lorsque vous dites plusieurs requêtes, vous entendez plusieurs instructions SQL comme dans:

UPDATE table1 SET a=b WHERE c;
UPDATE table2 SET a=b WHERE d;
UPDATE table3 SET a=b WHERE e;

Ou plusieurs appels de fonction de requête comme dans:

mySqlQuery(UPDATE table1 SET a=b WHERE c;)
mySqlQuery(UPDATE table2 SET a=b WHERE d;)
mySqlQuery(UPDATE table3 SET a=b WHERE e;)

Le premier peut être fait en utilisant un seul appel mySqlQuery si c'est ce que vous vouliez réaliser, appelez simplement la fonction mySqlQuery de la manière suivante:

mySqlQuery(UPDATE table1 SET a=b WHERE c; UPDATE table2 SET a=b WHERE d; UPDATE table3 SET a=b WHERE e;)

Cela exécutera les trois requêtes avec un seul appel mySqlQuery ().

code_burgar
la source
mySqlQuery () est une fonction personnalisée ou une fonction intégrée? Je veux en savoir plus à ce sujet.
Debashis
3
Il n'y a pas de différence significative entre l'envoi de trois requêtes individuellement ou sous la forme d'une requête multiple, sauf peut-être si votre fonction de requête ouvre une nouvelle connexion à chaque fois. Du point de vue de l'exécution côté serveur, c'est la même chose
Duncan