我在制定查询以满足以下条件时遇到困难(有一个基本的 CTE 查询工作),但我认为我遗漏/忽略了一些东西,希望能有所帮助(提前非常感谢!)。我尝试查看其他一些有关递归 CTE 的帖子,但不幸的是,我觉得在阅读这些帖子时无法回答我的问题。
给定一个包含以下列的
categories
表格:
`id` int - primary key
`limit_to` text[] - array of text / is nullable
`parent_id` int - references `id` / is nullable
with values:
id | limit_to | parent_id
-------------------------
1 | {'tc'} | null
-------------------------
2 | null | 1
-------------------------
3 | null | 2
-------------------------
4 | null | null
-------------------------
5 | {'ta'} | null
我正在尝试编写一个查询来过滤掉具有
limit_to IS NOT NULL
的记录(父/子关联)。在这种情况下,我期望行 1,2,3
和 5
被过滤掉,因为 1 的 limit_to
值为 {'tc'}
,其后代分别为 2
和 3
。行 5
也有一个不为空的值 {'ta'}
。因此在这种情况下,最终选择中只会返回第 4
行。
到目前为止我尝试过的查询:
with recursive tree as (
(
select
*
from
categories
where
limit_to is null
)
union all
(
select
categories.*
from
categories
inner join tree on tree.id = categories.parent_id
where
tree.limit_to is null
)
)
select
id,
parent_id
from
categories
where
id in (
select
id
from
tree
)
and limit_to is null
order by
id asc
但是,在这个示例查询中,我仍然看到行
1
的后代(2
和 3
),即使它们是 parent_id = 1
上的递归子代,由于其 limit_to
记录而被过滤掉有一个价值。我有一种感觉,我缺少放置一个额外的 WHERE
过滤器表达式,但我不完全确定它在哪里。
我还在研究一个查询,以匹配
limit_to IS NULL OR '''tc''' = ANY(limit_to)
来匹配仅具有该条件的记录(因此在这种情况下,行 5
将被消除/不返回,其他记录将返回),但我有一个感觉我无法让该查询完全正常工作,直到我明白我缺少什么条件来完全过滤 limit_to IS NULL
并确保子行被正确过滤掉。
我非常感谢任何关于我可能遗漏的内容/任何指针(但不是 null :P )的正确方向的见解,如何正确过滤查询,正如我根据上面描述的所期望的那样。谢谢!
当您递归地遍历树时,您需要保留某种标志,该标志表示当前记录的任何父记录中是否已看到
categories.limit_to is not null
的实例。如果新记录具有 join
,则此标志会在每个 true
更新为 categories.limit_to is not null
。然后,当您从cte
查询时,您可以简单地扫描包含false
标志的记录:
with recursive cte as (
select c.*, c.limit_to is not null f from categories c where c.parent_id is null
union all
select c.*, c1.f or c.limit_to is not null f from cte c1
join categories c on c.parent_id = c1.id
)
select id, limit_to, parent_id from cte where not f