【问题标题】:MySQL, update multiple tables with one queryMySQL,一次查询更新多个表
【发布时间】:2019-08-21 13:17:35
【问题描述】:

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

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

【问题讨论】:

  • 你能提供一个生成代码的例子吗?表之间是否有公用键?

标签: mysql sql sql-update


【解决方案1】:

假设我有Table1 主键_id 和一个布尔列doc_availabilityTable2 带有外键 _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

【讨论】:

    【解决方案2】:

    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“内连接”语法的原因。很容易忘记这个条件,而是获得一个完整的笛卡尔连接。
    【解决方案3】:
    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/…
    【解决方案4】:

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

    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 加入它们。有时,“等连接”一词用于指代这个习语。
    【解决方案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】:

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

    【讨论】:

    • 我会在哪里写程序?你能举个例子吗?
    • 赞成解释原子性的必要性 - 同样重要的是要认识到使用存储过程并不能单独保证一致性,您仍然需要使用事务;同样,事务可以在不使用存储过程的情况下执行,前提是它们在同一连接上执行。在这种情况下,使用多表更新就更好了。
    猜你喜欢
    • 2013-01-27
    • 1970-01-01
    • 1970-01-01
    • 2013-06-24
    • 2010-11-26
    • 1970-01-01
    • 1970-01-01
    • 2017-09-02
    相关资源
    最近更新 更多