MySQL,一次查询更新多个表

Posted

技术标签:

【中文标题】MySQL,一次查询更新多个表【英文标题】:MySQL, update multiple tables with one query 【发布时间】:2011-05-20 16:37:35 【问题描述】:

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

如何在 mysql 中使用单个查询更新多个表?

【问题讨论】:

你能提供一个生成代码的例子吗?表之间是否有公用键? 【参考方案1】:

BooksOrders 这两个表为例。如果我们在Orders 表中以特定顺序增加具有Order.ID = 1002 的书籍数量,那么我们还需要在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? 这样做与交易相比有什么优势?谢谢! @paulkon,我假设在使用事务时,会涉及很多开销,因为如果事务中的任何过程失败,则必须提供回滚。 使用此查询时的一般警告。 WHERE 子句为每个表单独评估。 Books.BookID=Orders.BookID 非常重要,没有它 Books 表更新将发生在所有行上,而不仅仅是针对具有指定 id 的行。有些教训是通过艰难的方式吸取的,这一教训是通过可怕的方式获得的。 @nheimann1 这就是为什么我总是建议人们使用 ANSI“内连接”语法的原因。很容易忘记这个条件,而是获得一个完整的笛卡尔连接。【参考方案2】:
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 指向正确的 @ 987654333@。但是每一本书都有太多的书要读,假设你知道那些有 author_id 对应于实际 author 的书是正确的。只有那些不存在的author_ids 是无效的。已经有一个供用户更新书籍详细信息的界面,开发人员不想仅仅为了这个问题而改变它。但是现有的接口做了一个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

【讨论】:

> 要查看将要更新的内容,您可以将其转换为 select 语句因此,如果我理解正确,由于INNER JOIN (= 不会在连接表中有对应项)不会更新,即使没有 where 子句?所以我可以 ``` UPDATE table1 INNER JOIN table2 ON table1.id = table2.table1_id SET ... ``` 而不是 ``` UPDATE table1 SET ... WHERE EXISTS( SELECT 1 FROM table2 WHERE table1_id = table. id) ``` @sisisisi 是的。请参阅此示例:dbfiddle.uk/…【参考方案3】:

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

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")。

【讨论】:

称之为“加入”有点大方 ;-) 很久以前,有一些数据库引擎在他们的 SQL 方言中甚至不支持JOIN,你只需在FROM 中列出多个表,并使用WHERE 加入它们。有时,“等连接”一词用于指代这个习语。【参考方案4】:

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

【讨论】:

我会在哪里写程序?你能举个例子吗? 赞成解释原子性的必要性 - 同样重要的是要认识到使用存储过程并不能单独保证一致性,您仍然需要使用事务;同样,事务可以在不使用存储过程的情况下执行,前提是它们在同一连接上执行。在这种情况下,使用多表更新就更好了。【参考方案5】:

当您说多个查询时,您的意思是多个 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() 是自定义函数还是内置函数?我想了解更多。 单独发送三个查询或作为多个查询发送三个查询没有显着差异,除非您的查询函数每次都打开一个新连接。从服务器端执行的角度来看,是一回事【参考方案6】:

假设我有 Table1 主键 _id 和一个布尔列 doc_availability; Table2 带有外键 _id 和 DateTime 列 last_update 并且我想将 Table1 中带有 _id 14 的文档的可用性更改为 0 即不可用并使用文档时的时间戳更新 Table2最近更新时间。以下查询将完成任务:

UPDATE Table1, Table2 
SET doc_availability = 0, last_update = NOW() 
WHERE Table1._id = Table2._id AND Table1._id = 14

【讨论】:

以上是关于MySQL,一次查询更新多个表的主要内容,如果未能解决你的问题,请参考以下文章

Access中UPDATE语句一次更新多个数据

mysql查询一次在单个查询中在多个表中插入记录

如何在mysql查询的更新语句中加入多个表[重复]

我如何编写将一次更新多个表的授权访问的 PLSQL 查询 |SQL Developer|

用于构建仪表板的多个 mysql 查询

MySQL 中的多个更新