此问题基于以下问题,但还有其他要求:PostgreSQL: How to find the last descendant in a linear "ancestor-descendant" relationship
基本上,我需要的是一个Postgre-SQL语句,它找到符合其他条件的线性“祖先 - 后裔”关系中的最后一个后代。
示例:
这里表“RELATIONSHIP_TABLE”的内容:
id | id_ancestor | id_entry | bool_flag
---------------------------------------
1 | null | a | false
2 | 1 | a | false
3 | 2 | a | true
4 | 3 | a | false
5 | null | b | true
6 | null | c | false
7 | 6 | c | false
特定层次结构中的每条记录都具有相同的“id_entry” 在这个例子中有3种不同的“祖先 - 后裔”关系:
1. 1 <- 2 <- 3 <- 4
2. 5
3. 6 <- 7
问题PostgreSQL: How to find the last descendant in a linear "ancestor-descendant" relationship显示了如何查找每个关系的最后一条记录。在上面的例子中:
1. 4
2. 5
3. 7
所以,这次我需要的是“id_entry”的最后一个后代,其“bool_flag”设置为true。在上面的例子中:
1. 3
2. 5
3. <empty result>
有人知道解决方案吗?
提前致谢:)
QStormDS
答案 0 :(得分:3)
表示为边缘列表的图形,树,链等通常用于递归公用表表达式 - 即WITH RECURSIVE
查询。
类似的东西:
WITH RECURSIVE walk(id, id_ancestor, id_entry, bool_flag, id_root, generation) AS (
SELECT id, id_ancestor, id_entry, bool_flag, id, 0
FROM RELATIONSHIP_TABLE
WHERE id_ancestor IS NULL
UNION ALL
SELECT x.id, x.id_ancestor, x.id_entry, x.bool_flag, walk.id_root, walk.generation + 1
FROM RELATIONSHIP_TABLE x INNER JOIN walk ON x.id_ancestor = walk.id
)
SELECT
id_entry, id_root, id
FROM (
SELECT
id, id_entry, bool_flag, id_root, generation,
max(CASE WHEN bool_flag THEN generation END ) OVER w as max_enabled_generation
FROM walk
WINDOW w AS (PARTITION BY id_root ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)
) x
WHERE generation = max_enabled_generation;
......虽然感觉真的应该有一个更好的方法来做到这一点,而不是追踪我们沿着每条路径走了多少代。
如果id_entry
对于树的所有成员都很常见,则可以避免需要跟踪id_root
。您应该在UNIQUE
上创建(id_entry, id)
约束,在FOREIGN KEY (id_entry, id_ancestor) REFERENCES (id_entry, id)
上创建外键约束以确保排序是一致的,然后使用:
WITH RECURSIVE walk(id, id_ancestor, id_entry, bool_flag, generation) AS (
SELECT id, id_ancestor, id_entry, bool_flag, 0
FROM RELATIONSHIP_TABLE
WHERE id_ancestor IS NULL
UNION ALL
SELECT x.id, x.id_ancestor, x.id_entry, x.bool_flag, walk.generation + 1
FROM RELATIONSHIP_TABLE x INNER JOIN walk ON x.id_ancestor = walk.id
)
SELECT
id_entry, id
FROM (
SELECT
id, id_entry, bool_flag, generation,
max(CASE WHEN bool_flag THEN generation END ) OVER w as max_enabled_generation
FROM walk
WINDOW w AS (PARTITION BY id_entry ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)
) x
WHERE generation = max_enabled_generation;
由于这会为您提供一个与根父母匹配的最终后代表,您现在只需使用常规WHERE
子句进行过滤,只需附加AND bool_flag
即可。如果您想要排除在任何点处bool_flag
设置为false的链,您可以在WHERE bool_value
查询的连接中添加RECURSIVE
。< / p>
SQLFiddle示例:http://sqlfiddle.com/#!12/92a64/3
答案 1 :(得分:1)
WITH RECURSIVE tail AS (
SELECT id AS opa
, id, bool_flag FROM boolshit
WHERE bool_flag = True
UNION ALL
SELECT t.opa AS opa
, b.id, b.bool_flag FROM boolshit b
JOIN tail t ON b.id_ancestor = t.id
)
SELECT *
FROM boolshit bs
WHERE bs.bool_flag = True
AND NOT EXISTS (
SELECT * FROM tail t
WHERE t.opa = bs.id
AND t.id <> bs.id
AND t.bool_flag = True
);
说明:选择所有设置了bool_flag的记录, 除了那些拥有bool_flag设定的后代(直接或间接)的人。这有效地选择了设置了标志的链的最后一条记录。