【问题标题】:Is it possible to update a mysql table only if all matching rows will get updated?只有当所有匹配的行都将更新时,是否可以更新 mysql 表?
【发布时间】:2016-04-21 01:53:49
【问题描述】:

我有一张像这样的桌子

| id | location | status | parent_id |   
-----------------------------------  
| 1  |  35      |   0    |   100     |  
| 2  |  35      |   1    |   100     |  
| 3  |  36      |   0    |   200     |  
| 4  |  36      |   0    |   200     |  

当且仅当具有特定 parent_id 的所有行都将状态设置为 0 时,我希望能够更新组并设置与某个 parent_id 匹配的行的状态 = 0。

用例是这样的: 一项活动 (parent_id) 可以在多个位置之一进行。每个活动都有一些子活动。仅当没有子活动开始时,活动才可以从一个位置移动到另一个位置。

是否可以在 MySQL 中进行事务处理?如果可以在不锁定整个表的情况下做到这一点,那么效率会高得多,但我不确定是否有一个单一的语句解决方案。

提前致谢。

编辑:我错过了一个重要的部分 - parent_id 是存储主要活动的表的 id。因此,此表与其自身在 (id, parent_id) 上的连接是不正确的。

【问题讨论】:

  • 如果具有该父项的所有行的状态均为 0,则相关行的状态已为 0。因此,无需更新。
  • 子活动也可以有子活动吗?
  • @gordonlinoff 我被困在如何确定该父项的所有行是否具有相同的状态,然后(并且只有这样)更改这些子活动的组(并将状态保留为 0)
  • @christhornhill 在这种情况下,我可以假设子活动不会有子活动 - 我认为使用 parent_id 可能是混淆的根源 - parent_id 是另一个表的 id 列

标签: mysql sql conditional updates transactional


【解决方案1】:

这个怎么样。我没有测试,性能可能不是最好的。

UPDATE t 
JOIN (SELECT parent_id, max(status) AS ma, min(status) AS mi FROM t2 GROUP BY parent_id HAVING ma<=0 AND mi>=-1) AS children 
  ON t.id=children.parent_id 
SET status = 0;

编辑
更改为使用 max an min 而不是 sum 以支持 status 可以小于 0 的事实,现在还允许更新子级中的 -1。

【讨论】:

  • 我猜,它可以通过在子查询中使用HAVING s = 0 来优化。在这种情况下,不需要WHERE children.s = 0
  • @stenix 我的错 - 我的问题遗漏了一个关键点 - 我刚刚意识到。 parent_id 实际上是另一个表的 id - 活动(即父母)在不同的表中,子活动(此表)在另一个表中。我已经更新了问题。
  • 没问题,然后加入那个表。我称它为 t2 或者可能是另一个应该称为 t2 的人,反正你明白了。
  • 这是一个遗留系统,我刚刚发现状态可以是-1,如果父母的所有孩子都是-1或0,我们可以更改组。这是我想出的一个看起来有点难看的查询,它似乎正在工作(需要做很多测试):update foo JOIN (select parent_id, count(*) as status_count from foo where parent_id = 200 and status in (0, -1) having status_count = (select count(*) as total_count from foo where parent_id = 200)) as x on x.parent_id = foo.parent_id SET status = 0, group_id = 98;
  • 我也更新了我的回复以支持 -1。您可能需要运行一些分析来确定哪个查询执行得最好。
【解决方案2】:

这是我尝试过的,它似乎正在工作:

UPDATE foo
    JOIN 
        (SELECT parent_id, COUNT(*) AS status_count FROM foo WHERE parent_id =   200 AND status IN (0, -1) 
         HAVING status_count = (SELECT COUNT(*) AS total_count FROM foo WHERE parent_id = 200)) 
    AS x ON x.parent_id = foo.parent_id
SET status = 0, group_id = 98;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-26
    相关资源
    最近更新 更多