MySQL,用一个查询更新多个表


131

我有一个更新三个表的函数,但是我使用三个查询来执行此操作。我希望使用一种更方便的方法进行良好实践。

如何通过单个查询更新MySQL中的多个表?


3
您能否提供生成代码的示例?这些表之间是否有公用键?
乔纳森·戴

Answers:


451

以两个表Books和为例Orders。在情况下,我们与增加特定顺序的图书数量Order.ID = 1002Orders表,然后我们还需要减少由在相同数量在我们的股票提供书籍总数Books表。

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

如果要在SQL查询中包含“ LIMIT”,是否必须说LIMIT 1或LIMIT 2?
Bluedayz 2014年

2
与交易相比,这样做有什么好处?谢谢!
paulkon,2014年

2
@paulkon,我假设使用事务时会涉及很多开销,因为如果事务中的任何过程失败,则必须进行回滚。
Thijs Riezebeek

27
使用此查询时的一般警告。对每个表分别评估WHERE子句。Books.BookID = Orders.BookID非常重要,如果没有它,Books表更新将发生在所有行上,而不仅是指定ID的行。一些经验教训是艰难的,这是可怕的。
nheimann1 2015年

1
@ nheimann1这就是为什么我总是建议人们使用ANSI“内部联接”语法的原因。忘记该条件而获得完整的笛卡尔联接太容易了。
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';

要查看将要更新的内容,可以将其转换为select语句,例如:

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';

使用与其他答案相同的表的示例:

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;

编辑:

只是为了好玩,让我们添加一些更有趣的东西。

假设您有个表格books和个表格authors。您books有一个author_id。但是,最初创建数据库时,没有设置外键约束,后来,前端代码中的错误导致一些书中添加了带有无效author_ids的书。作为一名DBA,您不需要经过所有这些books检查即可确定author_id应该是什么,因此决定由数据捕获器将修复books到正确的位置authors。但是,每本都有太多的书要经过,比方说,您知道具有author_id与实际相对应的的书author是正确的。只是那些不存在的author_id无效。用户已经有一个界面来更新书的详细信息,而开发人员不想仅仅为了这个问题而更改它。但是现有的界面会执行INNER JOIN authors,因此所有具有无效作者的书籍都将被排除。

您可以执行以下操作:插入诸如“未知作者”之类的伪作者记录。然后更新author_id所有不良记录的,以指向未知作者。然后,数据捕获器可以搜索作者设置为“未知作者”的所有书籍,查找正确的作者并进行修复。

您如何更新所有不良记录以指向未知作者?像这样(假设“未知作者” author_id是99999):

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

上述还将更新books是有一个NULL author_id对未知的作者。如果您不想要,当然可以添加AND books.author_id IS NOT NULL


35

您也可以使用联接对一个查询执行此操作,如下所示:

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

当然,然后发送此查询。您可以在此处阅读有关联接的更多信息:http : //dev.mysql.com/doc/refman/5.0/en/join.html。对于多个表的更新,还有一些限制和限制,您可以在此处阅读:http : //dev.mysql.com/doc/refman/5.0/en/update.html(仅ctrl + f“ join”)。


称其为“ join”有点慷慨;-)
underscore_d

2

这通常是存储过程的目的:在序列中实现多个SQL语句。使用回滚,可以确保将它们视为一个工作单元,即要么全部执行,要么都不执行,以保持数据一致。


我在哪里写程序?你能举个例子吗?
亚当斯基

1
投票赞成解释原子性的必要性-认识到使用存储过程并不能单独保证一致性,您仍然需要使用事务,这一点也很重要。同样,只要在同一连接上执行事务,就可以在不使用存储过程的情况下执行事务。在这种情况下,使用多表更新甚至更好。
邓肯

2

当您说多个查询时,是指多个SQL语句,如下所示:

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

或多个查询函数调用,如下所示:

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

如果您要实现单个方法,则可以使用单个mySqlQuery调用来完成前者,只需按以下方式调用mySqlQuery函数即可:

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

这将通过一个mySqlQuery()调用执行所有三个查询。


mySqlQuery()是自定义函数还是内置函数?我想了解更多。
Debashis 2012年

3
单独发送三个查询或作为多个查询发送三个查询之间没有显着差异,除非您的查询函数每次都打开一个新连接。从服务器端执行的角度来看,这是同一件事
Duncan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.