MySQL, actualice varias tablas con una consulta

132

Tengo una función que actualiza tres tablas, pero utilizo tres consultas para realizar esto. Deseo utilizar un enfoque más conveniente para las buenas prácticas.

¿Cómo puedo actualizar varias tablas en MySQL con una sola consulta?

Adamski
fuente
3
¿Puedes dar un ejemplo del código generado? ¿Hay una clave común entre las tablas?
Jonathan Day

Respuestas:

451

Tomemos el caso de dos mesas, Booksy Orders. En caso de que aumentemos el número de libros en un orden particular Order.ID = 1002en la Orderstabla, entonces también debemos reducir el número total de libros disponibles en nuestro inventario por el mismo número en la Bookstabla.

UPDATE Books, Orders
SET Orders.Quantity = Orders.Quantity + 2,
    Books.InStock = Books.InStock - 2
WHERE
    Books.BookID = Orders.BookID
    AND Orders.OrderID = 1002;
Irfan
fuente
Si quiero incluir "LIMIT" a la consulta SQL, ¿debo decir LIMIT 1 o LIMIT 2?
Bluedayz
2
¿Cuál es la ventaja de hacer esto frente a una transacción? ¡Gracias!
paulkon
2
@paulkon, supongo que cuando se usan transacciones, hay muchos gastos generales involucrados ya que las reversiones deben estar disponibles si falla algún procedimiento en la transacción.
Thijs Riezebeek
27
Advertencia general al usar esta consulta. La cláusula WHERE se evalúa por separado para cada tabla. Books.BookID = Orders.BookID es muy importante, sin ella La actualización de la tabla de libros ocurriría en todas las filas y no solo para la fila con la identificación especificada. Algunas lecciones se aprenden de la manera difícil, esta se aprendió de una manera aterradora.
nheimann1
1
@ nheimann1 Y esa es exactamente la razón por la que siempre recomiendo que la gente use la sintaxis de "unión interna" ANSI. Es demasiado fácil olvidar esa condición y, en cambio, obtener una combinación cartesiana completa.
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';

Para ver qué va a actualizar esto, puede convertirlo en una instrucción select, por ejemplo:

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 ejemplo que usa las mismas tablas que la otra respuesta:

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;

EDITAR:

Solo por diversión, agreguemos algo un poco más interesante.

Digamos que tienes una tabla de booksy una tabla de authors. Tu bookstienes un author_id. Pero cuando se creó originalmente la base de datos, no se configuraron restricciones de clave externa y más tarde un error en el código front-end provocó que algunos libros se agregaran con correos no válidos author_id. Como administrador de bases de datos , no desea tener que pasar por todo esto bookspara verificar cuál author_iddebería ser, por lo que se toma la decisión de que los capturadores de datos arreglen el bookspunto a la derecha authors. Pero hay demasiados libros para revisar cada uno y digamos que sabes que los que tienen una s que no son válidos. Ya hay una interfaz para que los usuarios actualicen los detalles del libro y los desarrolladores no quieren cambiar eso solo por este problema. Pero la interfaz existente hace unauthor_id que corresponde con un real authorson correctos. Son solo los que no existenauthor_idINNER JOIN authors, por lo que se excluyen todos los libros con autores no válidos.

Lo que puede hacer es esto: inserte un registro de autor falso como "Autor desconocido". Luego actualice elauthor_id de todos los registros incorrectos para señalar al autor Desconocido. Luego, los capturadores de datos pueden buscar todos los libros con el autor establecido en "Autor desconocido", buscar el autor correcto y corregirlo.

¿Cómo se actualizan todos los registros incorrectos para señalar al autor desconocido? Así (suponiendo que el autor desconocido author_ides 99999):

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

Lo anterior también actualizará booksque tenga un NULL author_idautor desconocido. Si no quieres eso, por supuesto que puedes agregar AND books.author_id IS NOT NULL.

Wodin
fuente
35

También puede hacer esto con una consulta usando una combinación como esta:

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

Y luego simplemente envíe esta consulta, por supuesto. Puede leer más sobre las combinaciones aquí: http://dev.mysql.com/doc/refman/5.0/en/join.html . También hay un par de restricciones para ordenar y limitar las actualizaciones de múltiples tablas que puede leer aquí: http://dev.mysql.com/doc/refman/5.0/en/update.html (solo ctrl + f "unirse").

Stephen Searles
fuente
Es un poco generoso llamarlo "unirse" ;-)
underscore_d
2

Por lo general, para eso están los procedimientos almacenados: para implementar varias instrucciones SQL en una secuencia. Con las reversiones, puede asegurarse de que se traten como una unidad de trabajo, es decir, que se ejecuten todas o ninguna de ellas, para mantener la coherencia de los datos.

SteveCav
fuente
¿Dónde escribiría el procedimiento? ¿podría por favor dar un ejemplo?
Adamski
1
Se votó a favor por explicar la necesidad de la atomicidad: también es importante darse cuenta de que el uso de procedimientos almacenados no solo garantiza la coherencia, sino que aún debe usar las transacciones; asimismo, las transacciones se pueden realizar sin utilizar un procedimiento almacenado, siempre que se realicen a través de la misma conexión. En este caso, el uso de una actualización de varias tablas es aún mejor.
Duncan
2

Cuando dice múltiples consultas, quiere decir múltiples sentencias SQL como en:

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

O múltiples llamadas a funciones de consulta como en:

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

Todo lo anterior se puede hacer usando una sola llamada mySqlQuery si eso es lo que quería lograr, simplemente llame a la función mySqlQuery de la siguiente manera:

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

Esto ejecutará las tres consultas con una llamada mySqlQuery ().

code_burgar
fuente
mySqlQuery () es una función personalizada o una función incorporada? Quiero saber más sobre esto.
Debashis
3
No hay una diferencia significativa entre enviar tres consultas individualmente o como una consulta múltiple, excepto quizás si su función de consulta abre una nueva conexión cada vez. Desde el punto de vista de la ejecución del lado del servidor, es lo mismo
Duncan