JOIN设置返回功能结果

fas*_*nji 4 sql postgresql join lateral set-returning-functions

我正在尝试连接返回行的表和函数:

SELECT p.id, p.name, f.action, f.amount
FROM person p
JOIN calculate_payments(p.id) f(id, action, amount) ON (f.id = p.id);
Run Code Online (Sandbox Code Playgroud)

此函数为每个id返回0,1行或更多行.该查询适用于PostgreSQL 9.3,但在9.1上它显示以下错误:

ERROR:  invalid reference to FROM-clause entry for table "p"
HINT:  There is an entry for table "p", but it cannot be referenced from this part of the query
Run Code Online (Sandbox Code Playgroud)

我无法将函数中的计算移出到查询中.根据我的理解,我
不能使用JOIN LATERAL这是9.3中的新功能.
这个问题有解决方法吗?

Erw*_*ter 11

在Postgres 9.1中:

SELECT name, (f).*  -- note the parentheses!
FROM  (SELECT name, calculate_payments(id) AS f FROM person) sub;
Run Code Online (Sandbox Code Playgroud)

假设您的函数具有明确定义的具有列名称的返回类型(id, action, amount)- 问题中缺少信息.
还假设您的函数始终返回相同的函数id(在这种情况下这是多余的并且可能会被优化).

相同的更详细的形式:

SELECT sub.id, sub.name, (sub.f).action, (sub.f).amount  -- parentheses!
FROM  (
   SELECT p.id, p.name, calculate_payments(p.id) AS f(id, action, amount)
   FROM   person p
) sub;
Run Code Online (Sandbox Code Playgroud)

SELECT列表中的设置返回函数会产生多行.但这是一个非标准的,有些古怪的特征.LATERALpg 9.3+中的新功能更可取.

可以在同一步骤中分解行类型:

SELECT *, (calculate_payments(p.id)).*  -- parentheses!
FROM   person p
Run Code Online (Sandbox Code Playgroud)

但是由于Postgres查询规划器的弱点,这导致每列评估一次函数:

或者在你的情况下:

SELECT p.id, p.name
     , (calculate_payments(p.id)).action
     , (calculate_payments(p.id)).amount
FROM   person p
Run Code Online (Sandbox Code Playgroud)

同样的问题:多重评估.

确切地说,相当于第9.3页的解决方案是:

SELECT p.id, p.name, f.action, f.amount
FROM   person p
LEFT   JOIN LATERAL calculate_payments(p.id) f ON TRUE;
Run Code Online (Sandbox Code Playgroud)

保留结果中的行,其中函数返回0行.

如果您不关心这一点,可以简化第9.3页:

SELECT p.id, p.name, f.action, f.amount
FROM   person p, calculate_payments(p.id) f;
Run Code Online (Sandbox Code Playgroud)

密切相关的答案: