SELECT 中对 set-returning 函数的支持是 PostgreSQL 扩展,也是 IMO 非常奇怪的扩展。它被广泛认为已弃用,最好尽可能避免。
尽可能避免使用 SRF-in-SELECT
现在LATERAL 在 9.3 中得到支持,两个主要用途之一已经不复存在。如果您想将一个 SRF 的输出用作另一个 SRF 的输入,则以前必须在 SELECT 中使用 set-returning 函数; LATERAL 不再需要它。
其他用途将在 9.4 中被替换,当添加 WITH ORDINALITY 时,允许您保留 set-returning 函数的输出顺序。这是目前主要的剩余用途:将两个 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)