使用递归 CTE 查询在 PostgreSQL 中进行故障过滤

问题描述 投票:0回答:1

我在制定查询以满足以下条件时遇到困难(有一个基本的 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 )的正确方向的见解,如何正确过滤查询,正如我根据上面描述的所期望的那样。谢谢!

sql postgresql recursion common-table-expression
1个回答
0
投票

当您递归地遍历树时,您需要保留某种标志,该标志表示当前记录的任何父记录中是否已看到

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

参见小提琴

© www.soinside.com 2019 - 2024. All rights reserved.