使用相同的 CASE 子查询有条件地更新多个列

问题描述 投票:0回答:1

当前使用 PostgreSQL 16.4。我查看了这篇文章,但它没有涵盖我的用例。

我想有条件地更新具有相同条件的两个(或更多)列,因此我不必重写它。这是一个非常简单的例子,当然我的情况比

TRUE
复杂很多。

create table test (a INT, b INT);

我可以这样做,但条件重复了。

update test SET a = CASE WHEN TRUE THEN 1 END, b = CASE WHEN TRUE THEN 2 END;

理想情况下我会这样做,但我收到错误:

update test SET (a, b) = (CASE WHEN TRUE THEN (1, 2) END);

ERROR:  source for a multiple-column UPDATE item must be a sub-SELECT or ROW() expression

如果我确实更改为子查询,我也会收到错误:

update test SET (a, b) = (SELECT CASE WHEN TRUE THEN (1, 2) END);

ERROR:  number of columns does not match number of values

如何编写子查询以便更新将 select 的输出视为 2 个值?如果我单独运行这个 SELECT ,我确实会得到 2 个值,所以我觉得我在某处缺少一些显式转换。

SELECT CASE WHEN TRUE THEN (1, 2) END
产生
1,2
 类型的 
RECORD

postgresql sql-update subquery
1个回答
0
投票

创建并填充

test
:

DROP TABLE IF EXISTS test;

CREATE TABLE test (
  id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  a INT,
  b INT
);

INSERT INTO
  test (a, b)
VALUES
  (0, 1),
  (11, 12);

SELECT *
  FROM test
  ORDER BY id;

test
的初始内容为:

id a b
1 0 1
2 11 12

最简单的情况是要求在满足条件时分配值,否则将列设置为

NULL
。 如果
a
是偶数,以下命令将 1 分配给
b
,将 2 分配给
a

UPDATE test
SET (a, b) = (SELECT 1, 2 WHERE a % 2 = 0);

test
的内容为:

id a b
1 1 2
2

当要求根据条件的评估分配替代值时,会出现更复杂的情况。下一个命令演示了处理这种情况的方法。将

test
恢复到其初始内容后,运行以下命令,当
a
为偶数时交换
b
a
,否则增加
a
b

UPDATE test
SET
  (a, b) = (
    SELECT
      a,
      b
    FROM (SELECT a % 2 = 0 AS met) c
    CROSS JOIN LATERAL (SELECT b AS a, a AS b
                          WHERE c.met
                        UNION ALL
                        SELECT a + 1 AS a, b + 1 AS b
                          WHERE NOT c.met) n);

test
的内容将是:

id a b
1 1 0
2 12 13

捕获条件表达式的计算结果消除了重复表达式的需要,这使得代码更易于维护且更高效。 使用

UNION ALL
是因为保证两个子查询中只有一个会返回一行。

© www.soinside.com 2019 - 2024. All rights reserved.