问题描述
CREATE TYPE IDType AS (id uuid);
drop function F_ItemPath;
CREATE OR REPLACE FUNCTION F_ItemPath (item record)
RETURNS TABLE (item_id uuid,depth numeric)
AS $$
BEGIN
return QUERY
WITH recursive item_path AS (
SELECT ic.parent_item_id,depth=1
from item_combination ic,item i
WHERE ic.child_item_id=i.id
UNION all
SELECT ic.parent_item_id,depth=ip.depth + 1
FROM item_path ip,item_combination ic WHERE ip.parent_item_id=ic.child_item_id
)
SELECT item_id=ip.parent_item_id,depth=ip.depth FROM item_path ip;
END; $$
LANGUAGE plpgsql;
select * from F_ItemPath(('55D6F516-7D8F-4DF3-A4E5-1E3F505837A1','FFE2A4D3-267C-465F-B4B4-C7BB2582F1BC'))
有两个问题:
sql Error [42703]: ERROR: column ip.depth does not exist
Where: PL/pgsql function f_itempath(record) line 3 at RETURN QUERY
我期望的是我可以正常使用该函数并且可以从其他表中提供参数。
这是您可以尝试的完整查询:
http://sqlfiddle.com/#!15/9caba/1
我在 DBEAVER 应用程序中进行了查询,它会有一些不同的错误消息。
我建议你可以在 sqlfiddle 之外试验它。
解决方法
表达式 depth=1
测试列 depth
是否等于值 1 并返回一个布尔值。但是你从来没有给这个布尔表达式一个合适的名字。
此外,您不能将数字与布尔值相加,因此表达式 depth=ip.depth + 1
试图将 1
与 true
或 false
的值相加——这显然失败了。如果确实有效,它会再次将该值与列 depth
中的值进行比较。
您是否打算使用名称 1
为值 depth
设置别名?然后你需要在递归部分使用1 as depth
和ip.depth + 1 as depth
。
在最后的选择中你有同样的错误 - 使用布尔表达式而不是列别名
还强烈建议使用 30 多年前 SQL 标准中引入的显式 JOIN 运算符。
使用 PL/pgSQL 来包装 SQL 查询也有点矫枉过正。一个SQL函数就够了。
使用无类型记录作为参数似乎非常可疑。它不允许您使用例如访问列item.id
。但是鉴于您的示例调用,您似乎只想为查询的锚点(非递归)部分传递多个 ID。最好使用数组或 varadic 参数来完成,后者允许使用逗号列出多个参数。
所以你可能想要这样的东西:
drop function f_itempath;
CREATE OR REPLACE FUNCTION f_itempath(variadic p_root_id uuid[])
RETURNS TABLE (item_id uuid,depth integer)
as
$$
WITH recursive item_path AS (
SELECT ic.parent_item_id,1 as depth
FROM item_combination ic
WHERE ic.child_item_id = any(p_root_id) --<< no join needed to access the parameter
UNION all
SELECT ic.parent_item_id,ip.depth + 1
FROM item_path ip
JOIN item_combination ic ON ip.parent_item_id = ic.child_item_id
)
SELECT ip.parent_item_id as item_id,ip.depth
FROM item_path ip;
$$
language sql
stable;
然后就可以这样调用了(注意:参数周围没有括号)
select *
from f_itempath('55d6f516-7d8f-4df3-a4e5-1e3f505837a1','ffe2a4d3-267c-465f-b4b4-c7bb2582f1bc');
select *
from f_itempath('55d6f516-7d8f-4df3-a4e5-1e3f505837a1','ffe2a4d3-267c-465f-b4b4-c7bb2582f1bc','df366232-f200-4254-bad5-94e11ea35379');
select *
from f_itempath('55d6f516-7d8f-4df3-a4e5-1e3f505837a1');