With 子句:嵌套树
With clause : nesting trees
我有一个带有兄弟顺序的树状层次结构。我需要添加对其他树的引用。
这是数据:
drop table if exists org; CREATE TABLE org(id int primary key, name text, boss int, sibling int, ref int) without rowid;
INSERT INTO org VALUES(0, 'Alice', NULL, null, null);
INSERT INTO org VALUES(1, 'Bob', 0, null, null);
INSERT INTO org VALUES(2, 'Cindy', 0, 1, null);
INSERT INTO org VALUES(3, 'Dave', 1, 4, 7);
INSERT INTO org VALUES(4, 'Emma', 1, null, null);
INSERT INTO org VALUES(5, 'Fred', 2, null, null);
INSERT INTO org VALUES(6, 'Gail', 2, 5, null);
INSERT INTO org VALUES(7, 'Helen', NULL, null, null);
INSERT INTO org VALUES(8, 'Igor', 7, null, null);
INSERT INTO org VALUES(9, 'Jerome', 7, 8, null);
Dave 引用了 Helen 领导的树。
我添加了 refs 子句:
WITH RECURSIVE
refs(id, name, boss, sibling, ref, lref) AS (
SELECT id, name, boss, sibling, ref, 0 FROM org
UNION ALL
SELECT org.id, org.name, org.boss, org.sibling, org.ref, refs.lref+1
FROM org JOIN refs ON org.id=refs.ref
),
sibs(id, name, boss, lref, lsib) AS (
SELECT id, name, boss, lref, 0 FROM refs
WHERE sibling IS NULL
UNION ALL
SELECT refs.id, refs.name, refs.boss, refs.lref, sibs.lsib + 1
FROM refs
JOIN sibs ON refs.boss = sibs.boss
AND refs.sibling = sibs.id
),
tree(id, name, lsib, lref, level) AS (
select id, name, 0, 0, 0 from org where id = 0
UNION ALL
SELECT sibs.id, sibs.name, sibs.lsib, sibs.lref, tree.level+1
FROM sibs JOIN tree ON sibs.boss=tree.id
ORDER BY 4 DESC, 5 DESC, 3 DESC
)
SELECT group_concat(name) FROM tree;
但结果不包括海伦的树:
Alice,Cindy,Gail,Fred,Bob,Dave,Emma
我怎样才能得到海伦树的完整结果:
Alice,Cindy,Gail,Fred,Bob,Dave,Helen,Igor,Jerome,Emma
编辑:
Bob 和 Cindy - 以及 Fred&Gail- 被颠倒了......实际预期结果是:
Alice,Bob,Dave,Helen,Igor,Jerome,Emma,Cindy,Fred,Gail
我认为您无法获得以下预期输出:
Alice,Cindy,Gail,Fred,Bob,Dave,Helen,Igor,Jerome,Emma
因为你要求对同一个案例有不同的结果:
- Cindy 和 Bob:同父异母。 Cindy 是 Bob 的兄弟姐妹,你想要 Cindy 而不是 Bob。
- 杰罗姆和伊戈尔:同父异母。杰罗姆是伊戈尔的兄弟姐妹,你想要伊戈尔而不是杰罗姆。
(如果 Cindy 必须在 Bob 之前打印,那么 Jerome 必须在 Igor 之前打印)
我认为预期的输出应该是:
Alice,Cindy,Gail,Fred,Bob,Dave,Helen,Jerome,Igor,Emma
或
Alice,Bob,Dave,Helen,Igor,Jerome,Emma,Cindy,Fred,Gail
第一种方法
我尝试了以下查询 (使用 refs.id 而不是 org.boss):
WITH RECURSIVE
refs(id, name, boss, sibling, ref, lref) AS (
SELECT id, name, boss, sibling, ref, 0 FROM org
UNION ALL
SELECT org.id, org.name, refs.id, org.sibling, org.ref, refs.lref+1
FROM org JOIN refs ON org.id=refs.ref
),
sibs(id, name, boss, lref, lsib,ref) AS (
SELECT id, name, boss, refs.lref, 0,ref FROM refs
WHERE sibling IS NULL
UNION ALL
SELECT refs.id, refs.name, refs.boss, refs.lref, sibs.lsib + 1,refs.ref
FROM refs
JOIN sibs ON refs.boss = sibs.boss
AND refs.sibling = sibs.id
),
tree(id, name, lsib, lref, level) AS (
select org.id, org.name, 0, 0, 0 from org
where id = 0
UNION ALL
SELECT sibs.id, sibs.name, sibs.lsib, sibs.lref, tree.level+1
FROM sibs JOIN tree ON sibs.boss = tree.id
ORDER BY 4 DESC, 5 DESC
)
select group_concat(name) from tree;
Alice,Bob,Dave,Helen,Igor,Jerome,Emma,Cindy,Fred,Gail
第二种方法
我使用了不同的方法:
WITH RECURSIVE
pc(id,name,parent,priority) AS(
select org.id,org.name,coalesce(refs.id,org.boss,-1) as "parent",
case
when refs.id is not null then 3
when sibls.id is not null then 2
when org.boss is not null then 1
else 0 end as "priority"
from org left join org as refs on org.id = refs.ref
left join org as sibls on org.id = sibls.sibling
where org.id > 0),
tree(id,name,parent,priority,level) AS(
select id,name,0,0,0 from org where id = 0
UNION ALL
select pc.id,pc.name,pc.parent,pc.priority,tree.level + 1 from pc
join tree on tree.id = pc.parent
order by 3 desc )
select group_concat(name) from tree
Alice,Bob,Dave,Helen,Igor,Jerome,Emma,Cindy,Fred,Gail
这会起作用:
SELECT LISTAGG(name, ', ') WITHIN GROUP (ORDER BY name)
FROM org
START WITH boss is null
CONNECT BY PRIOR id= boss
ORDER SIBLINGS BY sibling;
要求输出:
Alice, Bob, Cindy, Dave, Emma, Fred, Gail, Helen, Igor, Jerome
我有一个带有兄弟顺序的树状层次结构。我需要添加对其他树的引用。
这是数据:
drop table if exists org; CREATE TABLE org(id int primary key, name text, boss int, sibling int, ref int) without rowid;
INSERT INTO org VALUES(0, 'Alice', NULL, null, null);
INSERT INTO org VALUES(1, 'Bob', 0, null, null);
INSERT INTO org VALUES(2, 'Cindy', 0, 1, null);
INSERT INTO org VALUES(3, 'Dave', 1, 4, 7);
INSERT INTO org VALUES(4, 'Emma', 1, null, null);
INSERT INTO org VALUES(5, 'Fred', 2, null, null);
INSERT INTO org VALUES(6, 'Gail', 2, 5, null);
INSERT INTO org VALUES(7, 'Helen', NULL, null, null);
INSERT INTO org VALUES(8, 'Igor', 7, null, null);
INSERT INTO org VALUES(9, 'Jerome', 7, 8, null);
Dave 引用了 Helen 领导的树。
我添加了 refs 子句:
WITH RECURSIVE
refs(id, name, boss, sibling, ref, lref) AS (
SELECT id, name, boss, sibling, ref, 0 FROM org
UNION ALL
SELECT org.id, org.name, org.boss, org.sibling, org.ref, refs.lref+1
FROM org JOIN refs ON org.id=refs.ref
),
sibs(id, name, boss, lref, lsib) AS (
SELECT id, name, boss, lref, 0 FROM refs
WHERE sibling IS NULL
UNION ALL
SELECT refs.id, refs.name, refs.boss, refs.lref, sibs.lsib + 1
FROM refs
JOIN sibs ON refs.boss = sibs.boss
AND refs.sibling = sibs.id
),
tree(id, name, lsib, lref, level) AS (
select id, name, 0, 0, 0 from org where id = 0
UNION ALL
SELECT sibs.id, sibs.name, sibs.lsib, sibs.lref, tree.level+1
FROM sibs JOIN tree ON sibs.boss=tree.id
ORDER BY 4 DESC, 5 DESC, 3 DESC
)
SELECT group_concat(name) FROM tree;
但结果不包括海伦的树:
Alice,Cindy,Gail,Fred,Bob,Dave,Emma
我怎样才能得到海伦树的完整结果:
Alice,Cindy,Gail,Fred,Bob,Dave,Helen,Igor,Jerome,Emma
编辑:
Bob 和 Cindy - 以及 Fred&Gail- 被颠倒了......实际预期结果是:
Alice,Bob,Dave,Helen,Igor,Jerome,Emma,Cindy,Fred,Gail
我认为您无法获得以下预期输出:
Alice,Cindy,Gail,Fred,Bob,Dave,Helen,Igor,Jerome,Emma
因为你要求对同一个案例有不同的结果:
- Cindy 和 Bob:同父异母。 Cindy 是 Bob 的兄弟姐妹,你想要 Cindy 而不是 Bob。
- 杰罗姆和伊戈尔:同父异母。杰罗姆是伊戈尔的兄弟姐妹,你想要伊戈尔而不是杰罗姆。
(如果 Cindy 必须在 Bob 之前打印,那么 Jerome 必须在 Igor 之前打印)
我认为预期的输出应该是:
Alice,Cindy,Gail,Fred,Bob,Dave,Helen,Jerome,Igor,Emma
或
Alice,Bob,Dave,Helen,Igor,Jerome,Emma,Cindy,Fred,Gail
第一种方法
我尝试了以下查询 (使用 refs.id 而不是 org.boss):
WITH RECURSIVE
refs(id, name, boss, sibling, ref, lref) AS (
SELECT id, name, boss, sibling, ref, 0 FROM org
UNION ALL
SELECT org.id, org.name, refs.id, org.sibling, org.ref, refs.lref+1
FROM org JOIN refs ON org.id=refs.ref
),
sibs(id, name, boss, lref, lsib,ref) AS (
SELECT id, name, boss, refs.lref, 0,ref FROM refs
WHERE sibling IS NULL
UNION ALL
SELECT refs.id, refs.name, refs.boss, refs.lref, sibs.lsib + 1,refs.ref
FROM refs
JOIN sibs ON refs.boss = sibs.boss
AND refs.sibling = sibs.id
),
tree(id, name, lsib, lref, level) AS (
select org.id, org.name, 0, 0, 0 from org
where id = 0
UNION ALL
SELECT sibs.id, sibs.name, sibs.lsib, sibs.lref, tree.level+1
FROM sibs JOIN tree ON sibs.boss = tree.id
ORDER BY 4 DESC, 5 DESC
)
select group_concat(name) from tree;
Alice,Bob,Dave,Helen,Igor,Jerome,Emma,Cindy,Fred,Gail
第二种方法
我使用了不同的方法:
WITH RECURSIVE
pc(id,name,parent,priority) AS(
select org.id,org.name,coalesce(refs.id,org.boss,-1) as "parent",
case
when refs.id is not null then 3
when sibls.id is not null then 2
when org.boss is not null then 1
else 0 end as "priority"
from org left join org as refs on org.id = refs.ref
left join org as sibls on org.id = sibls.sibling
where org.id > 0),
tree(id,name,parent,priority,level) AS(
select id,name,0,0,0 from org where id = 0
UNION ALL
select pc.id,pc.name,pc.parent,pc.priority,tree.level + 1 from pc
join tree on tree.id = pc.parent
order by 3 desc )
select group_concat(name) from tree
Alice,Bob,Dave,Helen,Igor,Jerome,Emma,Cindy,Fred,Gail
这会起作用:
SELECT LISTAGG(name, ', ') WITHIN GROUP (ORDER BY name)
FROM org
START WITH boss is null
CONNECT BY PRIOR id= boss
ORDER SIBLINGS BY sibling;
要求输出:
Alice, Bob, Cindy, Dave, Emma, Fred, Gail, Helen, Igor, Jerome