简体   繁体   English

如何从递归CTE中排除条目?

[英]How do I exclude entries from a recursive CTE?

How can I exclude entries from a recursive CTW with Sqlite? 如何使用Sqlite从递归CTW中排除条目?

CREATE TABLE GroupMembers (
    group_id        VARCHAR,
    member_id       VARCHAR
);

INSERT INTO GroupMembers(group_id, member_id) VALUES
    ('1', '10'),
    ('1', '20'),
    ('1', '30'),
    ('1', '-50'),
    ('2', '30'),
    ('2', '40'),
    ('3', '1'),
    ('3', '50'),
    ('4', '-10'),
    ('10', '50'),
    ('10', '60');

I want a query that will give me the list of members (recursively) in the group. 我想要一个查询,该查询将给我(递归)组中的成员列表。 However, a member with the first character being '-' means that the id that comes after the minus is NOT in the group. 但是,第一个字符为“-”的成员表示减号后的id不在组中。

For example, the members of '1' are '10', '20', '30', and '-50'. 例如,“ 1”的成员是“ 10”,“ 20”,“ 30”和“ -50”。 '10', however, is a group so we need to add its children '50' and '60'. 但是,“ 10”是一个组,因此我们需要添加其子级“ 50”和“ 60”。 However, '-50' is already a member so we cannot include '50'. 但是,“-50”已经是成员,因此我们不能包含“ 50”。 In conclusion the members of '1' are '10', '20', '30', '-50', and '60'. 总之,“ 1”的成员是“ 10”,“ 20”,“ 30”,“-50”和“ 60”。

It seems like this query should work: 看来此查询应该工作:

WITH RECURSIVE members(id) AS (
    VALUES('1')
    UNION
    SELECT gm.member_id 
        FROM members m
        INNER JOIN GroupMembers gm ON mg.group_id=m.id
        LEFT OUTER JOIN members e ON '-' || gm.member_id=e.id
        WHERE e.id IS NULL
)
SELECT id FROM members;

But I get the error: multiple references to recursive table: members 但是我得到了错误: multiple references to recursive table: members

How can I fix/rewrite this to do what I want? 如何解决/重写此功能以执行我想要的操作?

Note: it doesnt matter whether the '-50' entry is returned in the result set. 注意:结果集中是否返回“ -50”并不重要。

I don't have a SQLite available for testing, but assuming the -50 also means that 50 should be excluded as well, I think you are looking for this: 我没有可用于测试的SQLite,但是假设-50也意味着也应该排除50 ,我想您正在寻找:

WITH RECURSIVE members(id) AS (
    VALUES('1')
    UNION
    SELECT gm.member_id 
    FROM GroupMembers gm 
      JOIN members m ON gm.group_id=m.id
    WHERE member_id not like '-%'
      AND not exists (select 1 
                      from groupMembers g2
                      where g2.member_id = '-'||gm.member_id)
)
SELECT id 
FROM members;

(The above works in Postgres) (以上工作在Postgres中)

You usually select from the base table in the recursive part and the join back to the actual CTE. 通常,您从递归部分的基表中进行选择,然后选择联接回实际的CTE。 The filtering of unwanted rows is then done with a regular where clause not by joining the CTE again. 然后,通过常规的where子句对不需要的行进行过滤, where无需再次加入CTE。 A recursive CTE is defined to terminate when the JOIN finds no more rows. 递归CTE定义为在JOIN没有找到更多行时终止。

SQLFiddle (Postgres): http://sqlfiddle.com/#!15/04405/1 SQLFiddle(Postgres): http ://sqlfiddle.com/#!15/04405/1

Edit after the requirements have changed (have been detailed): 需求更改后进行编辑 (已进行了详细说明):

As you need to exclude the rows based on their position (a detail that you didn't provide in your original question). 因为您需要根据行的位置排除行(原始问题中未提供的详细信息)。 The filter can only be done outside of the CTE. 只能在CTE 之外进行过滤。 Again I can't test this with SQLite, only with Postgres: 同样,我不能仅使用Postgres使用SQLite进行测试:

WITH RECURSIVE members(id, level) AS (
    VALUES('4', 1)
    UNION
    SELECT gm.member_id, m.level + 1
    FROM GroupMembers gm 
      JOIN members m ON gm.group_id=m.id
)
SELECT m.id, m.level
FROM members m
where id not like '-%'
  and not exists (select 1 
                  from members m2
                  where m2.level < m.level 
                    and m2.id = '-'||m.id);

Updated SQLFiddle: http://sqlfiddle.com/#!15/ec0f9/3 更新的SQLFiddle: http ://sqlfiddle.com/#!15/ec0f9/3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM