select子句中多个set-returns函数的预期行为是什么?

时间:2016-10-05 00:02:03

标签: sql postgresql cross-join set-returning-functions

我试图加入"交叉加入"有两个设置返回功能的结果,但在某些情况下,我没有得到"交叉连接",参见示例

行为1 :当设置的长度相同时,它会逐项匹配每一组

postgres=# SELECT generate_series(1,3), generate_series(5,7) order by 1,2;
 generate_series | generate_series 
-----------------+-----------------
               1 |               5
               2 |               6
               3 |               7
(3 rows)

行为2 :当设置的长度不同时,它会"交叉加入" s

postgres=# SELECT generate_series(1,2), generate_series(5,7) order by 1,2;
 generate_series | generate_series 
-----------------+-----------------
               1 |               5
               1 |               6
               1 |               7
               2 |               5
               2 |               6
               2 |               7
(6 rows)

我想我在这里不理解某事,有人可以解释一下这种行为吗?

编辑:另一个例子,比之前更奇怪

postgres=# SELECT generate_series(1,2) x, generate_series(1,4) y order by x,y;
 x | y 
---+---
 1 | 1
 1 | 3
 2 | 2
 2 | 4
(4 rows)

(注意:我接受回答标题问题的答案以及文档链接。)

3 个答案:

答案 0 :(得分:9)

Postgres 10或更新

为较小的集添加空值。使用generate_series()进行演示:

SELECT generate_series( 1,  2) AS row2
     , generate_series(11, 13) AS row3
     , generate_series(21, 24) AS row4;
row2 | row3 | row4
-----+------+-----
   1 |   11 |   21
   2 |   12 |   22
null |   13 |   23
null | null |   24

dbfiddle here

The manual for Postgres 10

  

如果查询的select中有多个set-returns函数   列表,行为类似于你从中获得的行为   函数转换为单个LATERAL ROWS FROM( ... ) FROM - 子句项。对于   来自底层查询的每一行,都有一个输出行使用   每个函数的第一个结果,然后使用第二个的输出行   结果,等等。如果某些返回函数产生   输出比其他输出少,空值代替缺失   数据,以便为一个基础行发出的总行数   与产生最多的set-returns函数相同   输出。因此,set-returns函数以“锁步”的方式运行,直到它们为止   都筋疲力尽,然后继续执行下一个   基础行。

这结束了传统的奇怪行为。

Postgres 9.6或更早

结果行数(有点令人惊讶!)是同一SELECT列表中所有集的 最低公共多重 。 (如果所有设置大小都没有公约数,则仅限于CROSS JOIN。)演示:

SELECT generate_series( 1,  2) AS row2
     , generate_series(11, 13) AS row3
     , generate_series(21, 24) AS row4;
row2 | row3 | row4
-----+------+-----
   1 |   11 |   21
   2 |   12 |   22
   1 |   13 |   23
   2 |   11 |   24
   1 |   12 |   21
   2 |   13 |   22
   1 |   11 |   23
   2 |   12 |   24
   1 |   13 |   21
   2 |   11 |   22
   1 |   12 |   23
   2 |   13 |   24

dbfiddle here

manual for Postgres 9.6 the chapter SQL Functions Returning Sets中记录,以及避免它的建议:

  

注意:在select中使用set-returns函数的关键问题   列表,而不是FROM子句,是不止一个   同一选择列表中的set-returns函数表现不佳   理智。 (如果这样做,实际得到的是一些输出   行等于行数的最小公倍数   由每个set-returns函数生成。LATERAL语法生成   调用多个set-returns函数时不太令人惊讶的结果,   通常应该使用。

大胆强调我的。

单个集合返回功能正常(但在FROM列表中仍然更清晰),但现在不鼓励使用同一个SELECT列表中的多个。在我们进行LATERAL连接之前,这是一个有用的功能。现在它只是历史的镇流器。

相关:

答案 1 :(得分:1)

我找不到任何相关的文档。但是,我可以描述我观察到的行为。

集合生成函数每个都返回有限行数。 Postgres似乎运行集生成函数,直到它们的所有都在最后一行 - 或者,当所有都返回到它们的第一行时更可能停止。从技术上讲,这将是系列长度的最小公倍数(LCM)。

我不确定为什么会这样。而且,正如我在评论中所说,我认为通常将函数放在from子句中会更好。

答案 2 :(得分:1)

the documentation中有关于此问题的唯一说明。我不确定这是否解释了所描述的行为。也许更重要的是不推荐使用这种功能:

  

目前,还可以在查询的选择列表中调用返回集的函数。对于查询自己生成的每一行,调用函数返回集,并为函数结果集的每个元素生成一个输出行。但请注意,此功能已弃用,可能会在将来的版本中删除。