MySQL,一次查询更新多个表
Posted
技术标签:
【中文标题】MySQL,一次查询更新多个表【英文标题】:MySQL, update multiple tables with one query 【发布时间】:2011-05-20 16:37:35 【问题描述】:我有一个更新三个表的函数,但我使用三个查询来执行此操作。我希望使用更方便的方法进行良好实践。
如何在 mysql 中使用单个查询更新多个表?
【问题讨论】:
你能提供一个生成代码的例子吗?表之间是否有公用键? 【参考方案1】:以Books
和Orders
这两个表为例。如果我们在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_id
s。作为 DBA,您不想通过所有这些 books
来检查 author_id
应该是什么,因此决定数据捕获器将修复 books
指向正确的 @ 987654333@。但是每一本书都有太多的书要读,假设你知道那些有 author_id
对应于实际 author
的书是正确的。只有那些不存在的author_id
s 是无效的。已经有一个供用户更新书籍详细信息的界面,开发人员不想仅仅为了这个问题而改变它。但是现有的接口做了一个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,一次查询更新多个表的主要内容,如果未能解决你的问题,请参考以下文章