Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 使用存储过程返回左外部联接中的记录集_Sql_Postgresql_Stored Procedures_Left Join_Lateral - Fatal编程技术网

Sql 使用存储过程返回左外部联接中的记录集

Sql 使用存储过程返回左外部联接中的记录集,sql,postgresql,stored-procedures,left-join,lateral,Sql,Postgresql,Stored Procedures,Left Join,Lateral,我尝试调用一个存储过程,在左外部联接中传递参数,如下所示: select i.name,sp.* from items i left join compute_prices(i.id,current_date) as sp(price numeric(15,2), discount numeric(5,2), taxes numeric(5,2)) on 1=1 where i.type = 404; compute\u prices()返回一组记录。 这是postgre

我尝试调用一个存储过程,在左外部联接中传递参数,如下所示:

select i.name,sp.*
from items i
left join compute_prices(i.id,current_date) as sp(price numeric(15,2), 
          discount numeric(5,2), taxes numeric(5,2)) on 1=1
where i.type = 404;
compute\u prices()
返回一组记录。
这是postgres显示的信息:

错误:对表“i”的FROM子句项的引用无效

…左连接计算价格(i.id,当前日期)

提示:表“i”有一个条目,但不能被引用 从查询的这一部分开始


这种查询在Firebird中有效。有没有一种方法可以通过使用查询使其工作?我不想创建另一个存储过程,它循环遍历项目并单独调用
compute_prices()

假设
compute_prices
函数总是返回一个包含3个价格的记录,您可以将其返回类型设置为
表(价格数字(15,2)、折扣数字(5,2)、税收数字(5,2))
,然后我相信你想要的可以表达为:

SELECT i.name, (compute_prices(i.id,current_date)).*
  FROM items i
WHERE i.type=404;

注意,在我看来,
1=1上的左连接与无约束的正常连接(或交叉连接)没有区别,我认为这个问题实际上与左连接无关。

我相信Daniel的答案也会起作用,但还没有尝试过。我知道我在一个名为logging的模式中有一个名为list_failed_jobs2的SP,还有一个名为Dual的伪表(就像在Oracle中一样),下面的语句适合我:

select * from Dual left join 
              (select * from logging.list_failed_jobs2()) q on 1=1;
注意,如果没有paren、correlation(q)或ON子句,SP调用将无法工作。我的SP也返回一组

因此,我怀疑这样的事情会对你有用:

select i.name,sp.*
from items i
left join (select * from compute_prices(i.id,current_date)) as sp on 1=1
where i.type = 404;

希望对您有所帮助。

一般来说,您可以通过以下方式扩展众所周知的行类型(也称为记录类型、复合类型、复合类型):

然而,如果你的描述是准确的

compute_prices sp返回一组记录

。。。我们正在处理匿名记录。Postgres不知道如何扩展匿名记录,绝望地抛出异常:

ERROR:  a column definition list is required for functions returning "record"
PostgreSQL 9.3 在Postgres 9.3中有一个解决方案
横向
,如下所述:

详情请参阅

PostgreSQL 9.2及更早版本 事情变得棘手。这里有一个解决方法:编写一个包装函数,将匿名记录转换为已知类型:

CREATE OR REPLACE FUNCTION compute_prices_wrapper(int, date)
  RETURNS TABLE (
            price    numeric(15,2)
           ,discount numeric(5,2)
           ,taxes    numeric(5,2)
          ) AS
$func$
    SELECT * FROM compute_prices($1, $2)
    AS t(price    numeric(15,2)
        ,discount numeric(5,2)
        ,taxes    numeric(5,2));
$func$ LANGUAGE sql;
然后您可以使用@Daniel提供的简单解决方案,只需插入包装器函数:

SELECT i.name, (compute_prices_wrapper(i.id, current_date)).*
FROM   items i
WHERE  i.type = 404;
PostgreSQL 8.3及更早版本 .
如果可能的话,你最好升级一下。但如果你不能:

CREATE OR REPLACE FUNCTION compute_prices_wrapper(int, date
           ,OUT price    numeric(15,2)
           ,OUT discount numeric(5,2)
           ,OUT taxes    numeric(5,2))
  RETURNS SETOF record AS
$func$
    SELECT * FROM compute_prices($1, $2)
    AS t(price    numeric(15,2)
        ,discount numeric(5,2)
        ,taxes    numeric(5,2));
$func$ LANGUAGE sql;
也适用于更高版本


正确的解决方案是修复函数
compute\u prices()
,首先返回一个众所周知的类型。返回记录集的函数通常是PITA。我只会用五米长的杆子戳它们。

我认为这目前是不可能的。如果我没有弄错,9.3将支持横向。我冒昧地在列定义列表中添加缺少的类型
numeric
。请检查这是否是您真正的意思。与仅从日志中选择*相比,我看不到它的好处。列出失败的作业2()。而且,
1=1
只是
TRUE
的一个笨拙的替代品,用于缺少适当的
布尔类型的数据库,如Oracle。我在一个包括数据库的环境中工作,比如Oracle,所以我坚持在任何地方都能工作。OP希望看到一个存储过程调用的示例,该调用返回一个与常规表联接的类型集,这是可行的。不,该声明本身没有实际用途;这只是为了演示语法。但我明白你的意思。我会编辑。不,添加的示例不起作用。不能在同一查询级别的函数调用中引用
i
。你需要已经提到的
LATERAL
(在即将发布的9.3版中引入)。啊,我想知道,但从来没有机会尝试过。我现在没有合适的SP可以玩。我想我已经没有主意了。
LEFT JOIN ON TRUE
与右表不返回行时的
CROSS JOIN
不同,在这种情况下,
LEFT JOIN
构造保留左表中的行。但您的简化替代方案碰巧做了正确的事情:“无行”会导致
NULL
值。然而,OP的函数似乎可能返回匿名记录(因为它提供了一个列定义列表)。在这种情况下,您不能使用
(记录)。*
表示法。@Erwin:关于针对空表的左连接的观点很好。至于函数return的类型,问题是“compute_prices sp返回一组记录”,因此这一点很明确。如果函数是用
returns setof record
(一组匿名记录)定义的,则查询将不起作用。无法使用
(记录)。*
语法展开匿名记录。它需要一个列定义列表,但我不知道有什么方法可以将其应用到这种查询中。我写了一个答案。@Erwin:我知道,这就是为什么我要改变返回类型,从我的观点来看,这是这里的实际问题。我的回答假设提问者选择了
SETOF RECORD
,而不知道这会有问题。是的,我在最后的评论中忽略了这一点。非常有用的答案。啊,太棒了!我明白你的意思了。我应该在我的函数中更改它。谢谢@Erwin。我想试试你的“返回表”选项,但它只在Postgres 8.4之后才可用。我用的是8.3。还有一个升级我的生产服务器的原因…@franbez:升级是一个很好的主意,但为了以防万一,我添加了一个过时版本的部分。我刚刚尝试了你的最后一个选项。我认为compute_prices的调用次数与查询表项返回的记录的调用次数相同(从items I中选择count(1)),其中I
SELECT i.name, (compute_prices_wrapper(i.id, current_date)).*
FROM   items i
WHERE  i.type = 404;
CREATE OR REPLACE FUNCTION compute_prices_wrapper(int, date
           ,OUT price    numeric(15,2)
           ,OUT discount numeric(5,2)
           ,OUT taxes    numeric(5,2))
  RETURNS SETOF record AS
$func$
    SELECT * FROM compute_prices($1, $2)
    AS t(price    numeric(15,2)
        ,discount numeric(5,2)
        ,taxes    numeric(5,2));
$func$ LANGUAGE sql;