gue*_*tli 12 postgresql cte recursive
我有这个有效的 CTE 示例。
我可以选择所有祖父母和所有孩子。
但是如何在一个语句中选择所有祖父母和所有孩子?
在这个例子中,如果我给“父亲”作为输入,我想要祖父,父亲,儿子作为输出。
我使用 PostgreSQL。但我认为这个问题应该是标准的SQL。
如果我使用 PostgreSQL 特定的语法,请纠正我。
DROP table if exists tree;
CREATE TABLE tree (
id SERIAL PRIMARY KEY,
name character varying(64) NOT NULL,
parent_id integer REFERENCES tree NULL
);
insert into tree values (1, 'Grandfather', NULL);
insert into tree values (2, 'Father', 1);
insert into tree values (3, 'Son', 2);
-- -------------------------------------
-- Getting all children works
WITH RECURSIVE rec (id) as
(
SELECT tree.id, tree.name from tree where name='Father'
UNION ALL
SELECT tree.id, tree.name from rec, tree where tree.parent_id = rec.id
)
SELECT *
FROM rec;
-- Result:
-- id | name
-- ----+--------
-- 2 | Father
-- 3 | Son
-- -------------------------------------
-- Getting all parents works
WITH RECURSIVE rec (id) as
(
SELECT tree.id, tree.name, tree.parent_id from tree where name='Father'
UNION ALL
SELECT tree.id, tree.name, tree.parent_id from rec, tree where tree.id = rec.parent_id
)
SELECT id, name
FROM rec;
-- Result
-- id | name
-- ----+-------------
-- 2 | Father
-- 1 | Grandfather
Run Code Online (Sandbox Code Playgroud)
以上是一个简化的工作示例。树的深度可达 100 级。在“父亲”之上可以有几个级别的祖先,在“父亲”之下可以有几个级别的后代。我要所有的祖先和所有的后代。
ype*_*eᵀᴹ 19
如果您想要所有祖先和所有后代,您可以将两个查询合二为一。使用两个 CTE 然后一个简单的UNION
:
WITH RECURSIVE
-- descendants
rec_d (id, name) AS
(
SELECT tree.id, tree.name FROM tree WHERE name = 'Father'
UNION ALL
SELECT tree.id, tree.name FROM rec_d, tree where tree.parent_id = rec_d.id
),
-- ancestors
rec_a (id, name, parent_id) AS
(
SELECT tree.id, tree.name, tree.parent_id FROM tree WHERE name = 'Father'
UNION ALL
SELECT tree.id, tree.name, tree.parent_id FROM rec_a, tree WHERE tree.id = rec_a.parent_id
)
SELECT id, name FROM rec_a
UNION
SELECT id, name FROM rec_d ;
Run Code Online (Sandbox Code Playgroud)
如果上面没有任何错误,我们可以改进它:
UNION
来UNION ALL
将最终更改为。JOIN .. ON
而不是隐式连接。查询变为:
WITH RECURSIVE
-- starting node(s)
starting (id, name, parent_id) AS
(
SELECT t.id, t.name, t.parent_id
FROM tree AS t
WHERE t.name = 'Father' -- this can be arbitrary
),
descendants (id, name, parent_id) AS
(
SELECT s.id, s.name, s.parent_id
FROM starting AS s
UNION ALL
SELECT t.id, t.name, t.parent_id
FROM tree AS t JOIN descendants AS d ON t.parent_id = d.id
),
ancestors (id, name, parent_id) AS
(
SELECT t.id, t.name, t.parent_id
FROM tree AS t
WHERE t.id IN (SELECT parent_id FROM starting)
UNION ALL
SELECT t.id, t.name, t.parent_id
FROM tree AS t JOIN ancestors AS a ON t.id = a.parent_id
)
TABLE ancestors
UNION ALL
TABLE descendants ;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
24229 次 |
最近记录: |