我正在尝试调用存储过程在左外连接中传递参数,如下所示:
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_prices()
返回一组记录
这是postgres显示的消息:
错误:对表“i”的FROM子句条目的无效引用
... left join compute_prices( i.id ,current_date)...
提示:表“i”有一个条目,但不能引用它 从这部分查询。
这种查询适用于Firebird。有没有办法可以通过使用查询使其工作?我不想创建另一个循环遍历项目的存储过程,并单独调用compute_prices()
。
答案 0 :(得分:5)
通常,您可以使用simple syntax @Daniel supplied扩展众所周知的行类型(a.k.a.记录类型,复杂类型,复合类型):
SELECT i.name, (compute_prices(i.id, current_date)).*
FROM items i
WHERE i.type = 404;
但是,如果您的描述准确无误......
compute_prices sp返回一组记录。
...我们正在处理匿名记录。 Postgres不知道如何扩展匿名记录并绝望地抛出一个EXCEPTION:
ERROR: a column definition list is required for functions returning "record"
Postgres 9.3中有一个解决方案。 LATERAL
,如@a_horse in the comments所述:
SELECT i.name, sp.*
FROM items i
LEFT JOIN LATERAL compute_prices(i.id,current_date) AS sp (
price numeric(15,2)
,discount numeric(5,2)
,taxes numeric(5,2)
) ON TRUE
WHERE i.type = 404;
manual中的详细信息。
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 has just reached EOL and is unsupported as of now (Feb. 2013)。
因此,如果可能的话,你最好升级。但如果你不能:
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_prices()
以返回一个众所周知的类型。返回SETOF record
的函数通常是PITA。我只戳了一个五米高的那些。
答案 1 :(得分:3)
假设compute_prices
函数始终返回包含3个价格的记录,您可以将其返回类型设为TABLE (price numeric(15,2), discount numeric(5,2),taxes numeric(5,2))
,然后我相信您想要的内容可以表示为:
SELECT i.name, (compute_prices(i.id,current_date)).*
FROM items i
WHERE i.type=404;
请注意,在我看来,LEFT JOIN ON 1=1
与无约束的正常JOIN(或CROSS JOIN)没有区别,我将该问题解释为与左连接实际上无关。
答案 2 :(得分:1)
我相信丹尼尔的回答也会奏效但尚未尝试过。我知道我在名为logging的模式中有一个名为list_failed_jobs2的SP,以及一个名为Dual的虚拟表(如在Oracle中),以下语句适用于我:
select * from Dual left join
(select * from logging.list_failed_jobs2()) q on 1=1;
注意,没有parens,correlation(q)或ON子句,SP调用将不起作用。我的SP也会返回SETOF。
因此,我怀疑这样的事情会对你有用:
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;
希望有所帮助。