我正在尝试使用我有限的SQL技能来构建递归CTE查询。 我有两个表格来建模家谱:
CREATE TABLE "Relation" (
"id" integer not null primary key autoincrement,
"person1Id" integer,
"person2Id" integer,
foreign key("person1Id") references "Person"("id"),
foreign key("person2Id") references "Person"("id"));
CREATE TABLE "Person" (
"id" integer not null primary key autoincrement,
"name" varchar(255),
"gender" varchar(255),
"bornToId" integer,
foreign key("bornToId") references "Relation"("id"));
我试图制作一个sqlfiddle,但我一直在哎呀,出了点问题',所以我会在这里粘贴插页:
INSERT INTO `Person` (id,name,gender,bornToId) VALUES
(1,'William I','M',NULL),
(2,'Matilde of Flanders','F',NULL),
(3,'William Rufus','M',1),
(4,'Henry I','M',1),
(5,'Matilde of Scotland','F',NULL),
(6,'William Adelin','M',2),
(7,'Matilde Holy Roman Empress','F',2),
(8,'Geoffrey of Anjou','M',NULL),
(9,'Henry II','M',3),
(10,'Eleanor of Aquitane','F',NULL),
(11,'Richard I','M',4),
(12,'John','M',4),
(13,'Robert Curthose','M',1),
(14,'Adeliza','F',NULL),
(15,'Adela of Normandy','F',1),
(16,'Stephen II Henry','M',NULL),
(17,'Stephen of Blois','M',6);
INSERT INTO `Relation` (id,person1Id,person2Id) VALUES (1,1,2),
(2,4,5),
(3,7,8),
(4,9,10),
(5,4,14),
(6,15,16);
我首先将问题分解为子查询。这些都按照我的预期工作(sqlite 3.14.0,数据库浏览器,在Mac上):
找到0,1或多个关系的人(合作伙伴)
select
pers.id as id,
pers.name as name,
partner.id as partnerId,
partner.name as partnerName
from Person pers
join Relation
on pers.id = Relation.person1Id
or pers.id = Relation.person2Id
join Person partner
on (partner.id = Relation.person1Id and
partner.id <> pers.id)
or (partner.id = Relation.person2Id and
partner.id <> pers.id)
where pers.id = 4
找到一个人的父母(如果有的话)
select
parent1.id as parent1Id,
parent1.name as parent1Name,
parent2.id as parent2Id,
parent2.name as parent2Name,
parents.id as parentsId
from Person pers
left join Relation parents on pers.bornToId = parents.id
left join Person parent1 on parents.person1Id = parent1.id
left join Person parent2 on parents.person2Id = parent2.id
where pers.id = 4
将上述两个结合起来也有效,但我在此处省略了该查询。
找到属于关系的孩子
select pers.id, pers.name
from Person pers
where pers.bornToId = 1
现在,将所有这些放在一个递归的cte查询中会导致我出现问题。到目前为止,我的尝试导致了这个查询的怪物,但它只返回一条记录(&#34; 1&#34;&#34;威廉一世&#34;&#34; 2&#34;&#34; Matilde of法兰德斯&#34;&#34; NULL&#34;&#34; NULL&#34;&#34; NULL&#34;&#34; NULL&#34;),显然它没有进入递归
WITH FamilyTree (
id,
name,
partnerId,
partnerName,
parent1Id,
parent1Name,
parent2Id,
parent2Name,
parentsId
)
AS (
select
pers.id as id,
pers.name as name,
partner.id as partnerId,
partner.name as partnerName,
parent1.id as parent1Id,
parent1.name as parent1Name,
parent2.id as parent2Id,
parent2.name as parent2Name,
parents.id as parentsId
from Person pers
left join Relation
on pers.id = Relation.person1Id
or pers.id = Relation.person2Id
left join Person partner
on (partner.id = Relation.person1Id and
partner.id <> pers.id)
or (partner.id = Relation.person2Id and
partner.id <> pers.id)
left join Relation parents on pers.bornToId = parents.id
left join Person parent1 on parents.person1Id = parent1.id
left join Person parent2 on parents.person2Id = parent2.id
where pers.id = 1
union all
select
pers.id as id,
pers.name as name,
partner.id as partnerId,
partner.name as partnerName,
parent1.id as parent1Id,
parent1.name as parent1Name,
parent2.id as parent2Id,
parent2.name as parent2Name,
parents.id as parentsId
from Person pers
left join Relation
on pers.id = Relation.person1Id
or pers.id = Relation.person2Id
left join Person partner
on (partner.id = Relation.person1Id and
partner.id <> pers.id)
or (partner.id = Relation.person2Id and
partner.id <> pers.id)
left join Relation parents on pers.bornToId = parents.id
left join Person parent1 on parents.person1Id = parent1.id
left join Person parent2 on parents.person2Id = parent2.id
JOIN FamilyTree AS fam
ON pers.bornToId = fam.parentsId
)
select
id,
name,
partnerId,
partnerName,
parent1Id,
parent1Name,
parent2Id,
parent2Name
from FamilyTree
我花了很多时间在这上面,所以我觉得是时候问专家了。
如果您想知道,最终目标是拥有嵌套的javascript对象,例如:
{
...
relations: [{
...
children: [{
所以我可以在D3树中使用它。
答案 0 :(得分:1)
我应该匹配root用户关系的id,我没有在select中定义。
在这个修改过的cte查询中,它确实进入了一个递归,结果看起来很好。我仍然需要做一些检查,但我会发布这个以保存其他人找到这个特定错误的麻烦。
WITH FamilyTree (
id,
name,
partnerId,
partnerName,
parent1Id,
parent1Name,
parent2Id,
parent2Name,
parentsId,
relationId
)
AS (
select
pers.id as id,
pers.name as name,
partner.id as partnerId,
partner.name as partnerName,
parent1.id as parent1Id,
parent1.name as parent1Name,
parent2.id as parent2Id,
parent2.name as parent2Name,
parents.id as parentsId,
rel.id as relationId
from Person pers
left join Relation rel
on pers.id = rel.person1Id
or pers.id = rel.person2Id
left join Person partner
on (partner.id = rel.person1Id and
partner.id <> pers.id)
or (partner.id = rel.person2Id and
partner.id <> pers.id)
left join Relation parents on pers.bornToId = parents.id
left join Person parent1 on parents.person1Id = parent1.id
left join Person parent2 on parents.person2Id = parent2.id
where pers.id = 1
union all
select
pers.id as id,
pers.name as name,
partner.id as partnerId,
partner.name as partnerName,
parent1.id as parent1Id,
parent1.name as parent1Name,
parent2.id as parent2Id,
parent2.name as parent2Name,
parents.id as parentsId,
rel.id as relationId
from Person pers
left join Relation rel
on pers.id = rel.person1Id
or pers.id = rel.person2Id
left join Person partner
on (partner.id = rel.person1Id and
partner.id <> pers.id)
or (partner.id = rel.person2Id and
partner.id <> pers.id)
left join Relation parents on pers.bornToId = parents.id
left join Person parent1 on parents.person1Id = parent1.id
left join Person parent2 on parents.person2Id = parent2.id
JOIN FamilyTree AS fam
ON pers.bornToId = fam.relationId
)
select
id,
name,
partnerId,
partnerName,
parent1Id,
parent1Name,
parent2Id,
parent2Name
from FamilyTree