一种方式:SET x=CASE..END(任何 SQL)
是的,你可以这样做,但我怀疑它会提高性能,除非你的查询有很大的延迟。
如果查询是根据搜索值索引的(例如,如果id是主键),那么定位所需的元组非常非常快,并且在第一次查询之后,表将保存在内存中。
因此,在这种情况下,多个 UPDATE 并不是那么糟糕。
另一方面,如果条件需要全表扫描,更糟糕的是,表的内存影响很大,那么使用单个复杂查询会更好,即使评估 UPDATE 比简单 UPDATE 更昂贵(这得到内部优化)。
在后一种情况下,您可以这样做:
 UPDATE table SET posX=CASE
      WHEN id=id[1] THEN posX[1]
      WHEN id=id[2] THEN posX[2]
      ...
      ELSE posX END [, posY = CASE ... END]
 WHERE id IN (id[1], id[2], id[3]...);
总成本或多或少由以下公式给出:NUM_QUERIES * (COST_QUERY_SETUP + COST_QUERY_PERFORMANCE)。这样,您可以减少 NUM_QUERIES(从 N 个单独的 id 到 1),但 COST_QUERY_PERFORMANCE 上升(在 MySQL 5.28 中约为 3 倍;尚未在 MySQL 8 中测试)。
否则,我会尝试对 id 进行索引,或者修改架构。
这是一个 PHP 示例,我想我们有一个条件已经需要全表扫描,我可以将其用作键:
// Multiple update rules 
$updates = [
   "fldA='01' AND fldB='X'" => [ 'fldC' => 12, 'fldD' => 15 ],
   "fldA='02' AND fldB='X'" => [ 'fldC' => 60, 'fldD' => 15 ],
   ...
];
右侧表达式中更新的字段可以是一个或多个,必须始终相同(在这种情况下始终为 fldC 和 fldD)。可以删除此限制,但需要修改算法。
然后我可以通过循环构建单个查询:
$where = [ ];
$set   = [ ];
foreach ($updates as $when => $then) {
    $where[] = "({$when})";
    foreach ($then as $fld => $value) {
       if (!array_key_exists($fld, $set)) {
           $set[$fld] = [ ];
       }
       $set[$fld][] = $value;
    }
}
$set1 = [ ];
foreach ($set as $fld => $values) {
    $set2 = "{$fld} = CASE";
    foreach ($values as $i => $value) {
        $set2 .= " WHEN {$where[$i]} THEN {$value}";
    }
    $set2 .= ' END';
    $set1[] = $set2;
}
// Single query
$sql  = 'UPDATE table SET '
      . implode(', ', $set1)
      . ' WHERE '
      . implode(' OR ', $where);
另一种方式:ON DUPLICATE KEY UPDATE (MySQL)
在 MySQL 中,我认为您可以使用 multiple 更轻松地做到这一点INSERT ON DUPLICATE KEY UPDATE,假设 id 是主键,请记住不存在的条件(“id = 777”,没有 777)将被插入到表中,如果出现错误,可能会导致错误,例如,查询中未指定其他必需的列(声明为 NOT NULL):
INSERT INTO tbl (id, posx, posy, bazinga)
     VALUES (id1, posY1, posY1, 'DELETE'),
     ...
ON DUPLICATE KEY SET posx=VALUES(posx), posy=VALUES(posy);
DELETE FROM tbl WHERE bazinga='DELETE';
上面的 'bazinga' 技巧允许删除任何可能因不存在 id 而被无意插入的行(但在其他情况下,您可能希望插入的行保留)。
例如,来自一组收集的传感器的定期更新,但某些传感器可能尚未传输:
INSERT INTO monitor (id, value)
VALUES (sensor1, value1), (sensor2, 'N/A'), ...
ON DUPLICATE KEY UPDATE value=VALUES(value), reading=NOW();
(这是一个人为的情况,可能更合理的是锁定表,将所有传感器更新为 N/A 和 NOW(),然后只插入我们拥有的那些值)。
第三种方式:CTE(PostgreSQL,不确定SQLite3)
这在概念上与 INSERT MySQL 技巧几乎相同。如所写,它适用于 PostgreSQL 9.6:
WITH updated(id, posX, posY) AS (VALUES
    (id1, posX1, posY1), 
    (id2, posX2, posY2),
    ...
)
UPDATE myTable
    SET 
    posX = updated.posY,
    posY = updated.posY
FROM updated
WHERE (myTable.id = updated.id);