了解 SELECT 列表中的集合返回函数 (SRF)

tin*_*lyx 9 postgresql set-returning-functions

为什么在 SELECT 列表中使用 Set Returning Function (SRF) 与在 FROM 子句中使用 SRF 在行为上存在差异?

例如,对于返回 2 行的简单 SRF:

CREATE OR REPLACE FUNCTION gen_series(out integer, out int)
  RETURNS SETOF record AS $$
  SELECT 1,1
  UNION
  SELECT 2,2;
$$ LANGUAGE SQL;
Run Code Online (Sandbox Code Playgroud)

SELECT gen_series(); 返回两个单列行,每个行包含一条记录:

=>  gen_series 
------------
 (1,1)
 (2,2)
(2 rows)
Run Code Online (Sandbox Code Playgroud)

SELECT * FROM gen_series();返回扩展记录的两行:

=>  column1 | column2 
---------+---------
       1 |       1
       2 |       2
(2 rows)
Run Code Online (Sandbox Code Playgroud)

相比之下,如果 SRF 返回单个列,则在 SELECT 或 FROM 子句中调用 SRF 没有区别。例如:

=> SELECT generate_series(1,2);
 generate_series 
-----------------
               1
               2
(2 rows)

=> SELECT * FROM generate_series(1,2);
 generate_series 
-----------------
               1
               2
(2 rows)
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  1. 我不太明白为什么在第二种情况下,SRF 行为与第一种情况不同,只是因为返回的表只有一列。就类型、元组和集合而言,这真的是一致的行为吗?

  2. 导致不同行为的两种情况有什么区别?

  3. SRF可以用作如上所示的表格,但表格也可以用来代替SRF吗?例如

    SELECT my_table; 
    
    Run Code Online (Sandbox Code Playgroud)

显然,这是SELECT my_SRF();不可能的,但为什么是可能的,而 SELECT my_table;不允许(在关系和数学方面)?

Erw*_*ter 5

Postgres 对简单情况的处理方式有所不同。多列被视为复合类型(表行),仅使用 进行分解SELECT * FROM ...,而标量类型的单列被视为复合类型,没有添加复合类型包装器。因此产生与简单情况SELECT my_SRF()相同的结果。关于表函数的手册SELECT * FROM my_SRF()

表函数是生成一组行的函数,这些行由基本数据类型(标量类型)或复合数据类型(表行)组成。

我同意这很令人困惑,而且你不是第一个感到困惑的人。(不过,请考虑替代方案:在单个列周围添加复合类型包装器可能会更加令人困惑。)

但不像Postgres 10之前列表中的多个SRF 函数所发生的那样令人困惑。这个问题已被永久修复:SELECT

标准的 SQL 方式是将 SRF 函数移至FROM子句中。使用LATERAL联接对表列进行操作。手册建议:

LATERAL当调用多个返回集合的函数时,该语法产生的结果并不令人意外,因此通常应该使用该语法。