我有桌子
Table "public.menu_items"
Column | Type | Collation | Nullable | Default
-------------+---------+-----------+----------+---------
id | integer | | not null |
name | text | | |
parent_id | integer | | |
position | integer | | |
is_category | boolean | | |
我有这个记录树
Lesson1 (id: 1, parent_id: null, position: 1, is_category: false)
Category2 (id: 2, parent_id: null, position: 2, is_category: true)
|_ Lesson2.1 (id: 5, parent_id: 2, position: 1, is_category: false)
|_ Category2.2 (id: 6, parent_id: 2, position: 2, is_category: true)
|_ Lesson2.2.1 (id: 8, parent_id: 6, position: 1, is_category: false)
|_ Lesson2.2.2 (id: 9, parent_id: 6, position: 2, is_category: false)
|_ Lesson2.2.3 (id: 10, parent_id: 6, position: 3, is_category: false)
|_ Lesson2.2.4 (id: 11, parent_id: 6, position: 4, is_category: false)
|_ (Lesson2.3 (id: 7, parent_id: 2, position: 3, is_category: false)
Lesson3 (id: 3, parent_id: null, position: 3, is_category: false)
Category4 (id: 4, parent_id: null, position: 4, is_category: true)
我知道id
和position
的记录,例如id = 10,位置=3。(课程2.2.3)
我需要查询树中给定记录上方的所有课程(is_category = false)。就我们而言
Lesson1 (id: 1, parent_id: null, position: 1, is_category: false)
Lesson2.1 (id: 5, parent_id: 2, position: 1, is_category: false)
Lesson2.2.1 (id: 8, parent_id: 6, position: 1, is_category: false)
Lesson2.2.2 (id: 9, parent_id: 6, position: 2, is_category: false)
为此,我可能需要使用WITH RECURSIVE
。如何编写这样的查询?
更新
现在我的查询看起来像这样,但是它只获取祖先,我可能需要嵌套WITH RECURSIVE
来获取每个祖先的子代。
WITH RECURSIVE r AS
(SELECT *
FROM menu_items
WHERE parent_id =
(SELECT parent_id
FROM menu_items
WHERE id = 10)
AND POSITION < 3
UNION SELECT x.*
FROM menu_items x
JOIN r ON x.id = r.parent_id
OR (x.parent_id IS NULL
AND r.parent_id IS NULL
AND x.position <
(SELECT POSITION
FROM menu_items
WHERE id = r.id)))
SELECT *
FROM r;
答案 0 :(得分:1)
免责声明:我不确定我是否完全了解了您的用例(请参阅问题下方的注释)。但是总的来说,这是一个解决方案。也许您应该校准一些小东西...
WITH RECURSIVE rec_lessons AS (
SELECT
id,
position,
name,
parent_id,
position::text as path,
is_category
FROM
lessons
WHERE parent_id IS NULL
UNION ALL
SELECT
l.id,
l.position,
l.name,
l.parent_id,
rl.path || '.' || l.position,
l.is_category
FROM
lessons l
JOIN rec_lessons rl ON l.parent_id = rl.id
)
SELECT *
FROM rec_lessons
WHERE is_category = false
递归CTE始终由两部分组成,并由UNION
子句分隔。第一个查询是起点,第二个查询是递归部分。
首先,我们需要找到可能是您的树根的所有行。我以为这就是没有父母的全部。
对于递归,我们查询原始表中所有具有上一回合的id作为parent_id的行。这就是联接的作用。因此,一开始所有根都具有ids
(1,2,3,4)
。在第一个递归中,我们找到parent_ids
是(1,2,3,4)
之一的所有行。这样我们得到了带有ids
(5,6,7)
的行。这些行与UNION ALL
合并为起始结果。下一步是找到所有带有parent_ids
的行都是(5,6,7)
之一,依此类推。
我添加了可以描述树的路径。这在每个角落都得到扩展。
最后(在WITH
子句之外),我过滤了所有非类别。