使用 postgresql 查询递归
Recursion with postgresql query
我正在尝试获取 grandparent 数据的结束 child 数据。
我有不到 2 tables,
一个是具有 parent 和 child 数据的主 table,另一个是主 table 数据的关系 table。
根据这些数据,我想要 parent 数据及其结尾 child 数据。
为此,我尝试了以下递归查询,但没有获得任何相关数据。
最后我想在 java 批处理中以下面的方式使用这些数据。
如果我将child_data 331和327一一通过,那么它会分别提供以下结果。
@set ko_id = '331'
select parent_id,child_id,count(parent_id) from (
WITH RECURSIVE ancestors (parent_id) AS (
SELECT distinct t.parent_id ,t.parent_id as extra_id,t.child_id , msok.data_type -- and find all its ancestors
FROM public.data_relation AS t
JOIN data_relation AS a ON t.child_id = a.parent_id or t.child_id = a.child_id
left join data_master msok on msok.id = t.parent_id
where a.child_id = :ko_id
),
descendants (parent_id) AS (
SELECT parent_id ,extra_id as extra_id,child_id, data_type FROM ancestors
UNION ALL
SELECT t.child_id,d.parent_id as extra_id,t.child_id, msok.data_type -- and find all their descendants
FROM public.data_relation AS t
JOIN descendants AS d ON t.parent_id = d.parent_id
left join data_master msok on msok.id = t.child_id
)
SELECT
parent_id, extra_id, child_id, data_type
FROM
descendants where data_type ='1') abc group by parent_id,child_id
此查询应该有所帮助。第一个 CTE(“with”部分)提供了 table 中的所有关系。第二个CTE过滤器只结束child条记录出来。
最后一部分 - 主要查询 - 搜索 parents 将 331 作为 child 并显示给你。
with recursive result_q as (
select 1 debug_step, parent_data, child_data
from data_rel
union all
select debug_step + 1, q.parent_data, r.child_data
from data_rel r
join result_q q
on q.child_data = r.parent_data
),
parent_end_childs as (
select q.parent_data, q.child_data
from result_q q
where not exists (select 1 from data_rel r where r.parent_data = q.child_data)
order by parent_data, child_data)
select pec.*
from parent_end_childs pec
join parent_end_childs pec_1
on pec.parent_data = pec_1.parent_data
where pec_1.child_data = 331
您可以试试这个创建多级父子关系作为 jsonb 数组:
WITH RECURSIVE list (array_parent_child_data) AS
(
SELECT to_jsonb(array[t.parent_data, t.child_data])
FROM public.data_relation AS t
UNION ALL
SELECT t.parent_data || l.array_parent_child_data
FROM public.data_relation AS t
INNER JOIN list AS l
ON l.array_parent_child_data->0 = t.child_data
AND NOT l.array_parent_child_data @> to_jsonb(t.parent_data) -- this condition is to avoid loops
)
SELECT l2.array_parent_child_data->>0 :: integer AS parent_data
, l2.array_parent_child_data->>-1 :: integer AS end_child_data
FROM list AS l1
LEFT JOIN list AS l2
ON l1.array_parent_child_data <> l2.array_parent_child_data
AND l1.array_parent_child_data @> l2.array_parent_child_data
WHERE l1 IS NULL -- l2.array_parent_child_data is not included in any l1.array_parent_child_data
我正在尝试获取 grandparent 数据的结束 child 数据。
我有不到 2 tables, 一个是具有 parent 和 child 数据的主 table,另一个是主 table 数据的关系 table。
根据这些数据,我想要 parent 数据及其结尾 child 数据。
为此,我尝试了以下递归查询,但没有获得任何相关数据。
最后我想在 java 批处理中以下面的方式使用这些数据。
如果我将child_data 331和327一一通过,那么它会分别提供以下结果。
@set ko_id = '331'
select parent_id,child_id,count(parent_id) from (
WITH RECURSIVE ancestors (parent_id) AS (
SELECT distinct t.parent_id ,t.parent_id as extra_id,t.child_id , msok.data_type -- and find all its ancestors
FROM public.data_relation AS t
JOIN data_relation AS a ON t.child_id = a.parent_id or t.child_id = a.child_id
left join data_master msok on msok.id = t.parent_id
where a.child_id = :ko_id
),
descendants (parent_id) AS (
SELECT parent_id ,extra_id as extra_id,child_id, data_type FROM ancestors
UNION ALL
SELECT t.child_id,d.parent_id as extra_id,t.child_id, msok.data_type -- and find all their descendants
FROM public.data_relation AS t
JOIN descendants AS d ON t.parent_id = d.parent_id
left join data_master msok on msok.id = t.child_id
)
SELECT
parent_id, extra_id, child_id, data_type
FROM
descendants where data_type ='1') abc group by parent_id,child_id
此查询应该有所帮助。第一个 CTE(“with”部分)提供了 table 中的所有关系。第二个CTE过滤器只结束child条记录出来。
最后一部分 - 主要查询 - 搜索 parents 将 331 作为 child 并显示给你。
with recursive result_q as (
select 1 debug_step, parent_data, child_data
from data_rel
union all
select debug_step + 1, q.parent_data, r.child_data
from data_rel r
join result_q q
on q.child_data = r.parent_data
),
parent_end_childs as (
select q.parent_data, q.child_data
from result_q q
where not exists (select 1 from data_rel r where r.parent_data = q.child_data)
order by parent_data, child_data)
select pec.*
from parent_end_childs pec
join parent_end_childs pec_1
on pec.parent_data = pec_1.parent_data
where pec_1.child_data = 331
您可以试试这个创建多级父子关系作为 jsonb 数组:
WITH RECURSIVE list (array_parent_child_data) AS
(
SELECT to_jsonb(array[t.parent_data, t.child_data])
FROM public.data_relation AS t
UNION ALL
SELECT t.parent_data || l.array_parent_child_data
FROM public.data_relation AS t
INNER JOIN list AS l
ON l.array_parent_child_data->0 = t.child_data
AND NOT l.array_parent_child_data @> to_jsonb(t.parent_data) -- this condition is to avoid loops
)
SELECT l2.array_parent_child_data->>0 :: integer AS parent_data
, l2.array_parent_child_data->>-1 :: integer AS end_child_data
FROM list AS l1
LEFT JOIN list AS l2
ON l1.array_parent_child_data <> l2.array_parent_child_data
AND l1.array_parent_child_data @> l2.array_parent_child_data
WHERE l1 IS NULL -- l2.array_parent_child_data is not included in any l1.array_parent_child_data