6

我正在尝试加入返回行的表和函数:

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);

此函数为每个 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

我无法将计算从函数移到查询中。
据我了解,我不能使用JOIN LATERAL这是 9.3 中的一个新功能。
这个问题有什么解决方法吗?

4

1 回答 1

23

在 Postgres 9.1中:

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

假设您的函数具有明确定义的返回类型和列名(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;

列表中的集合返回函数SELECT导致多行。但这是一个非标准且有些古怪的功能。pg 9.3+ 中的新LATERAL功能更可取。

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

SELECT *, (calculate_payments(p.id)).*  -- parentheses!
FROM   person p

但是由于 Postgres 查询计划器的弱点,这将对每个结果列评估一次函数:

或者在你的情况下:

SELECT p.id, p.name
     , (calculate_payments(p.id)).action
     , (calculate_payments(p.id)).amount
FROM   person p

同样的问题:重复评估。

准确地说,相当于 pg 9.3+ 中的解决方案是这样的,在函数返回 0 行的结果中保留行:

SELECT p.id, p.name, f.action, f.amount
FROM   person p
LEFT   JOIN LATERAL calculate_payments(p.id) f ON true;

如果你不关心这个,你可以在 pg 9.3+ 中简化:

SELECT p.id, p.name, f.action, f.amount
FROM   person p, calculate_payments(p.id) f;

密切相关:

于 2015-03-04T11:47:06.620 回答