如何使用多个 WHERE 子句在单个查询中更新多个 ROW?

Tol*_*leo 3 mysql

我怎样才能简化这些查询

UPDATE `table` SET `col1` = 'abc', `col2` = 'xyz' WHERE `col3` = '1';
UPDATE `elbat` SET `col1` = `a`, `col2` = 'x' WHERE `col3` = '1';
UPDATE `elbat` SET `col1` = `b`, `col2` = 'y' WHERE `col3` = '2';
UPDATE `elbat` SET `col1` = `c`, `col2` = 'z' WHERE `col3` = '3';
Run Code Online (Sandbox Code Playgroud)

进入这样的事情?

UPDATE `table` a, `elbat` b 
SET a.`col1` = 'abc', a.`col2` = 'xyz' WHERE a.`col3` = '1',
SET b.`col1` = `a`, b.`col2` = 'x' WHERE b.`col3` = '1',
SET b.`col1` = `b`, b.`col2` = 'y' WHERE b.`col3` = '2',
SET b.`col1` = `c`, b.`col2` = 'z' WHERE b.`col3` = '3';
Run Code Online (Sandbox Code Playgroud)

运行单查询而不是四查询

And*_*y M 6

评论

可以根据某些条件更新行。还可以在 MySQL 中的一条语句中更新多个表。

不过,后者是否是一个好主意还有待商榷。目标表将连接在一起进行更新,当我说“连接”时,我的意思是更广泛的含义:您不必指定连接条件,在这种情况下,它们将是交叉连接。在交叉联接中,当至少一个表具有多于一行时,另一个表将不可避免地在联接集中出现重复的行。如果两者都有多行,则两者都会将它们相乘。有点违反直觉,MySQL 仍然只会更新每个受影响的行一次,但在这种情况下我会避免进行多表更新,即使仅仅是因为违反直觉。

方法一

无论如何,继续您的具体示例,确实没有连接条件,每个表上只有一个过滤器。您可以在 UPDATE 的 WHERE 子句中指定这些过滤器。现在,为了选择更新每列的值,您可以使用 CASE 表达式。完整的 UPDATE 语句可能如下所示:

UPDATE
  A, B
SET
  A.col1 = 'abc',
  A.col2 = 'xyz',
  B.col1 = CASE B.col3
             WHEN '1' THEN 'a'
             WHEN '2' THEN 'b'
             WHEN '3' THEN 'c'
           END,
  B.col2 = CASE B.col3
             WHEN '1' THEN 'x'
             WHEN '2' THEN 'y'
             WHEN '3' THEN 'z'
           END
WHERE
  A.col3 = '1'
  AND B.col3 IN ('1', '2', '3')
;
Run Code Online (Sandbox Code Playgroud)

您可以看到,您必须在 CASE 表达式中为 forB.col1和 for重复相同的条件集B.col2。有办法避免这种情况吗?

方法2

就在这里。B.col1您可以将和 的目标值B.col2以及过滤值排列为B.col3派生表,并将其连接到BUPDATE 子句中,如下所示:

UPDATE
  A,
  B
    INNER JOIN
    (
      SELECT 'a' AS col1, 'x' AS col2, '1' AS col3
      UNION ALL
      SELECT 'b', 'y', '2'
      UNION ALL
      SELECT 'c', 'z', '3'
    ) AS fltr ON B.col3 = fltr.col3
SET
  A.col1 = 'abc',
  A.col2 = 'xyz',
  B.col1 = fltr.col1,
  B.col2 = fltr.col2
WHERE
  A.col3 = '1'
;
Run Code Online (Sandbox Code Playgroud)

连接还充当 的过滤器B,因此您可以省略 WHERE 子句中的过滤器。

您可以在以下位置找到每种方法的演示:dbfiddle 徽标数据库<>小提琴:

更好的方法

最后,正如本文开头和评论中所述,您可以为每个表使用单独的 UPDATE 语句。对于脚本的读者和数据库引擎来说,结果的意图都是明确的。更简单的脚本使后者能够有更多的优化选项。

使用上述任一方法进行表B更新,但分别执行两个表:

UPDATE
  A
SET
  A.col1 = 'abc',
  A.col2 = 'xyz'
WHERE
  A.col3 = '1'
;
Run Code Online (Sandbox Code Playgroud)
UPDATE
  B
    INNER JOIN
    (
      SELECT 'a' AS col1, 'x' AS col2, '1' AS col3
      UNION ALL
      SELECT 'b', 'y', '2'
      UNION ALL
      SELECT 'c', 'z', '3'
    ) AS fltr ON B.col3 = fltr.col3
SET
  B.col1 = fltr.col1,
  B.col2 = fltr.col2
;
Run Code Online (Sandbox Code Playgroud)

将更新拆分为单独的语句还有另一个原因。由于对于单个 UPDATE 语句需要连接表,因此两个表都有要更新的行非常重要。如果一个表没有匹配的行,那么即使另一个表有,也不会更新。这是因为与非空集交叉连接的空集仍然会产生空集。

因此,如果至少一个表没有与条件匹配的行,则单个 UPDATE 语句将没有行可处理。单独的 UPDATE 不会发生这种情况,因为每个表都将使用自己的表,而不管另一个表的内容如何,​​因此,一个表中缺少行不会影响另一个表的更新。

  • 我的意思是:在一条语句中使用“UPDATE tableA ...;”,在另一条语句中使用“UPDATE tableB ...;”。不要在一条语句中更新 2 个表。 (2认同)