【问题标题】:JOIN on set returning function resultsJOIN 集合返回函数结果
【发布时间】:2015-03-04 11:08:44
【问题描述】:

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

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 中的一项新功能。
这个问题有解决办法吗?

【问题讨论】:

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


    【解决方案1】:

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

    密切相关:

    【讨论】:

    • 谢谢@Ervin 我按照你的建议做了:SELECT p.id, p.name, sub.action, sub.amount FROM person p INNER JOIN (SELECT (calculate_payments(p1.id))。 * FROM person p1) sub ON (p.id = sub.id) 像这样的东西,它起作用了。
    • @faskunji:除了我所建议的不是。以这种方式,每行对函数进行多次评估。你可以有更便宜的。
    猜你喜欢
    • 1970-01-01
    • 2012-12-18
    • 1970-01-01
    • 2018-04-10
    • 1970-01-01
    • 2010-10-19
    • 2013-05-10
    • 1970-01-01
    • 2023-03-16
    相关资源
    最近更新 更多