我有两张桌子:
locations
:
locationid parentid
1
2 1
3 1
4 2
5 4
8 1
approvelog
:
locationid approved
4 True
8 True
我需要编写一个查询,该查询提供特定位置的所有子位置,但如果locationid被批准,则忽略它及其子项,即使这些子项未获批准也是如此。
简单来说,当遇到具有approved=True
的locationid时,忽略它及其所有子项(意味着停止递归此分支)。
例如:
我希望获得locationid=2
:
2
我希望获得locationid=8
:
Nothing
我希望获得locationid=1
:
1,2,3
4被批准所以忽略它和它的孩子。 8被批准,所以忽略它。
这是我的代码:
with recursive location_tree as (
select locationid, parentid
from locations
where locationid = 1 and not approved
union all
select child.locationid, child.parentid
from locations child
join location_tree parent on parent.locationid = child.parentid
where child.active
)
select array_agg(locationid)
from location_tree
这只是给出一个位置列表。
基本上我需要的是递归的“停止条件”。 如何更改它?
有人可以帮忙吗?
答案 0 :(得分:1)
这是我在PostgreSQL中用来让父母及其未经批准的孩子认为父母本身也未被批准的内容:
WITH recursive location_tree AS (
--PARENT
SELECT
p.locationid,
p.parentid
FROM
locations p
LEFT JOIN
approvelog pa ON pa.locationid = p.locationid AND pa.approved = TRUE
WHERE
p.locationid = 1
AND pa.locationid IS NULL --Exclude approved parent
UNION ALL
--CHILD
SELECT
c.locationid,
c.parentid
FROM
locations c
JOIN
location_tree p on p.locationid = c.parentid
LEFT JOIN
approvelog ca ON ca.locationid = c.locationid AND ca.approved = TRUE
WHERE
ca.locationid IS NULL --Exclude approved children
)
SELECT
array_agg(locationid)
FROM
location_tree
答案 1 :(得分:0)
我相信@ vanlee1987的答案很好。或者,您可以将其包装在函数中,并在函数本身内执行实际递归(而不是递归SQL)。例如:
CREATE OR REPLACE FUNCTION location_tree(location_id integer)
RETURNS integer[] AS
$BODY$
DECLARE
result integer[];
r locations%rowtype;
BEGIN
select array[l.locationid]
into result
from
locations l
left join approvelog a on
l.locationid = a.locationid
where
l.locationid = location_id and
(a.approved is null or a.approved = false);
for r in
select
l.locationid, l.parentid
from
locations l
where
l.parentid = any (result)
loop
result := array_cat(result, location_tree(r.locationid));
end loop;
return result;
end
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
实现:
select location_tree(1); // yields {1,2,3}
select location_tree(2); // yields {2}
select location_tree(8); // yields {}