在Postgresql中,如果您不需要两个相同大小的数组,它们将一个数组中的每个值与另一个数组中的一个排成一行,但如果两个数组的大小不同,则它将每个值与每个值连接起来从另一个。
select unnest(ARRAY[1, 2, 3, 4, 5]::bigint[]) as id,
unnest(ARRAY['a', 'b', 'c', 'd', 'e']) as value
将返回
1 | "a"
2 | "b"
3 | "c"
4 | "d"
5 | "e"
但是
select unnest(ARRAY[1, 2, 3, 4, 5]::bigint[]) as id, -- 5 elements
unnest(ARRAY['a', 'b', 'c', 'd']) as value -- 4 elements
order by id
将返回
1 | "a"
1 | "b"
1 | "c"
1 | "d"
2 | "b"
2 | "a"
2 | "c"
2 | "d"
3 | "b"
3 | "d"
3 | "a"
3 | "c"
4 | "d"
4 | "a"
4 | "c"
4 | "b"
5 | "d"
5 | "c"
5 | "b"
5 | "a"
这是为什么?我假设正在使用某种隐式规则,并且我想知道我是否可以明确地执行它(例如,如果我想要第二种样式,当我有匹配的数组大小,或者我想要在一个数组中缺少值时视为NULL)。
答案 0 :(得分:4)
SELECT
中对集合返回函数的支持是PostgreSQL扩展,IMO非常奇怪。它被广泛认为已被弃用,并尽可能避免使用。
SELECT
现在9.3中支持LATERAL
,其中一个主要用途已经消失。如果你想使用一个SRF的输出作为另一个SRF的输入,那么在SELECT
中使用set-returns函数是必要的。 LATERAL
不再需要。
当添加WITH ORDINALITY
时,其他用法将在9.4中被替换,允许您保留set-returns函数的输出顺序。这是目前剩余的主要用途:将两个SRF的输出压缩成匹配值对的行集。 WITH ORDINALITY
最期待unnest
,但适用于任何其他SRF。
PostgreSQL在这里使用的逻辑(对于它最初在古代历史中引入的任何IMO疯狂的原因)是:每当任一函数产生输出时,发出一行。如果只有一个函数产生了输出,则再次扫描另一个函数的输出以获得所需的行。如果两者都没有产生输出,则停止发射行。
使用generate_series
更容易看到。
regress=> SELECT generate_series(1,2), generate_series(1,2);
generate_series | generate_series
-----------------+-----------------
1 | 1
2 | 2
(2 rows)
regress=> SELECT generate_series(1,2), generate_series(1,3);
generate_series | generate_series
-----------------+-----------------
1 | 1
2 | 2
1 | 3
2 | 1
1 | 2
2 | 3
(6 rows)
regress=> SELECT generate_series(1,2), generate_series(1,4);
generate_series | generate_series
-----------------+-----------------
1 | 1
2 | 2
1 | 3
2 | 4
(4 rows)
在大多数情况下,你真正想要的是两者的简单交叉连接,这是非常理智的。
regress=> SELECT a, b FROM generate_series(1,2) a, generate_series(1,2) b;
a | b
---+---
1 | 1
1 | 2
2 | 1
2 | 2
(4 rows)
regress=> SELECT a, b FROM generate_series(1,2) a, generate_series(1,3) b;
a | b
---+---
1 | 1
1 | 2
1 | 3
2 | 1
2 | 2
2 | 3
(6 rows)
regress=> SELECT a, b FROM generate_series(1,2) a, generate_series(1,4) b;
a | b
---+---
1 | 1
1 | 2
1 | 3
1 | 4
2 | 1
2 | 2
2 | 3
2 | 4
(8 rows)
当你想要以锁定步骤,成对方式(如zip
)运行多个函数时,当前的主要异常是当前无法对连接执行的。
WITH ORDINALITY
这将在9.4中使用WITH ORDINALITY
进行改进,而广告虽然效率低于SELECT中的多次SRF扫描(除非添加了优化程序改进),但这样做会更加精明。
假设您希望将1..3
和10..40
与多余元素的空值配对。使用with ordinality
(仅限PostgreSQL 9.4):
regress=# SELECT aval, bval
FROM generate_series(1,3) WITH ORDINALITY a(aval,apos)
RIGHT OUTER JOIN generate_series(1,4) WITH ORDINALITY b(bval, bpos)
ON (apos=bpos);
aval | bval
------+------
1 | 1
2 | 2
3 | 3
| 4
(4 rows)
当srf-in-from改为返回时:
regress=# SELECT generate_series(1,3) aval, generate_series(1,4) bval;
aval | bval
------+------
1 | 1
2 | 2
3 | 3
1 | 4
2 | 1
3 | 2
1 | 3
2 | 4
3 | 1
1 | 2
2 | 3
3 | 4
(12 rows)