像@klin provided,使用data-modifying CTE。
但是,虽然您可以在SELECT 列表中使用集合返回函数(出于历史原因),但如果可能的话,最好将其移至FROM 列表中。自从LATERAL 加入 Postgres 9.3 以来,这几乎总是可能的。
特别是如果您需要提取 多个 列(从您评论的 行类型)。多次调用unnest() 也是低效的。
WITH upd AS (
UPDATE notis n
SET notis = '{}'::noti_record_type[] -- explicit cast optional
FROM (
SELECT notis
FROM notis
WHERE user_id = 2
FOR UPDATE
) old_n
WHERE old_n.user_id = n.user_id
RETURNING old_n.notis
)
SELECT n.*
FROM upd u, unnest(u.notis) n; -- implicit CROSS JOIN LATERAL
如果数组可以为空并且您想保留空/NULL 结果,请使用LEFT JOIN LATERAL ... ON true:
此外,同一SELECT 中的多个集合返回函数可能会表现出令人惊讶的行为。避免这种情况。如果您确实需要并行取消嵌套 多个 数组:
相关:
解释我之前的错误
当从集合返回函数将行类型(或复合或记录类型)分配给列列表时,Postgres 有一个奇怪。人们可能期望行类型字段被视为 one 列并分配给相应的列,但事实并非如此。它会自动分解(仅一行层!)并逐个元素分配。
所以这不能按预期工作:
SELECT (my_row).*
FROM upd u, unnest(u.notis) n(my_row);
但确实如此 (like @klin commented):
SELECT (my_row).*
FROM upd u, unnest(u.notis) my_row;
或者我最终使用的更简单的版本:
SELECT n.*
FROM upd u, unnest(u.notis) n;
还有另一个奇怪:当只为具有一列的集合返回函数提供 一个 别名时,它似乎被用作table 别名 and 作为 column 别名。 SELECT 列表中的名称返回 column 值。所以所有这些都做同样的事情:
SELECT n FROM unnest (ARRAY[1,2,3]) n;
SELECT n FROM unnest (ARRAY[1,2,3]) n(n);
SELECT n FROM unnest (ARRAY[1,2,3]) t(n);
即使这样!移除单个元素的行包装器:
SELECT t FROM unnest (ARRAY[1,2,3]) t(n);
但是,一旦有多个元素,行包装器就会被保留:
SELECT t FROM unnest (ARRAY[1,2,3]) WITH ORDINALITY t(n); -- requires 9.4+
困惑?还有更多。对于复合类型(手头的情况),使用复合类型,例如:
CREATE TYPE my_type AS (id int, txt text);
虽然这按预期工作:
SELECT n FROM unnest(ARRAY[(1, 'foo')::my_type, (2, 'bar')::my_type]) n;
惊喜在这里:
SELECT n FROM unnest(ARRAY[(1, 'foo')::my_type, (2, 'bar')::my_type]) n(n);
这就是我遇到的错误:在提供列列表时,Postgres 会分解行并一一分配提供的名称。在SELECT 列表中引用n 不会返回复合类型,而只会返回(重命名的)第一个元素。我粗心地期待行类型并尝试使用(my_row).* 进行分解 - 但它只返回第一个元素。
再说一遍:
SELECT t FROM unnest(ARRAY[(1, 'foo')::my_type, (2, 'bar')::my_type]) t(n);
(请注意,第一个元素已重命名为"n"!)
SQL Fiddle 一起玩。
在 Postgres 9.4+(不在小提琴中)中,unnest() 的新形式采用多个数组参数:
SELECT *
FROM unnest (ARRAY[(1, 'foo')::my_type, (2, 'bar')::my_type]
, ARRAY[(3, 'baz')::my_type, (4, 'bak')::my_type]) n;
但不是:
SELECT *
FROM unnest (ARRAY[(1, 'foo')::my_type, (2, 'bar')::my_type]
, ARRAY[(3, 'baz')::my_type, (4, 'bak')::my_type]) n(a, b);
我不太喜欢如何处理这一切。它经常让包括我在内的人们感到困惑,而且我多年来一直在使用它。