CTE 显示我所有的亲戚,无论生成和扩展(SQL Server 2016)
CTE to display all my relatives regardless of the generation and extension (SQL Server 2016)
只想正确了解如何最好地构建 CTE。
我追求的是不分世代和后代的所有亲人
例如:
- Parents/Aunts/Uncles/,盛大Parents,盛大Parents
- 我的 Siblings/My Kids/My 侄子侄女
我可以弄清楚如何在之前或之后获取,但使用两个 CTE(递归)并可能使用临时 table 作为参考来获取 nieces/nephews 并将它们合并为 1 个结果。
还有其他利用递归 CTE 的选项吗?
如果你能引导我找到最好的想法或答案,我将不胜感激。
我在想"Get Parent"然后"Get Child",这个child有没有另一个parent(和之前的不一样),这个parent a child 然后循环返回。
下面是我的样本数据
预期结果:
上面是完美的树...但是如果有哪个 71 是我的 half-relative
60 | 70
60 | 71
61 | 71
62 | 72 -- where 72 is half-sibling of 70 and 62 is a new spouse
so the new expected result will be inclusive of 60, 70, 71, 72
不确定您要找什么。
我认为没有任何递归的必要。
仍然没有文本形式的真实数据。
declare @t table(rel1 int,rel2 int)
insert into @t values(70,80),(70,81),(80,90)
,(80,91),(81,810),(81,812),(91,100),(91,101)
,(91,102),(91,103),(91,104),(90,1020),(90,1030),(90,1040),(90,1010)
,(90,1050),(100,1020),(100,1030),(100,1040)
,(100,1050),(101,1001),(101,1002),(810,81001),(100,1010)
declare @input int=70
select t.rel1 from @t t
UNION
select t.rel2 from @t t
第二种方法,
select t.rel1 from @t t
inner join @t c
on t.rel2=c.rel1
union
select t.rel2 from @t t
inner join @t c
on t.rel1=c.rel2
Get Parent, Get Child, any Half relatives then Loop back approach
Recursive CTE and Loop
/* relatives table */
create table #relationship
(rel1 int,rel2 int)
insert into #relationship
values
(60,70),
(60,71),
(61,71),
(62,71), -- half relative ie. 62 as Step-spouse considered as extended family
(62,72), -- half relative ie. 72 as half-sibling of 71
(70,80),
(70,81)
,(80,90)
,(80,91)
,(81,810)
,(81,812)
,(91,100)
,(91,101)
,(91,102)
,(91,103)
,(91,104)
,(90,1020)
,(90,1030)
,(90,1040)
,(90,1010)
,(90,1050),
(100,1020),
(100,1030),
(100,1040)
,(100,1050)
,(101,1001)
,(101,1002)
,(101,2001)
,(810,81001)
,(100,1010)
/* you as 100 */
declare @inputval int = 100
/* need these variables for condition and switching values */
declare @initval int
declare @testval int
/* working table to get all child and parents and extended family */
create table #workingtable
(child int,
parent int
)
CREATE CLUSTERED INDEX IDX_rel1 ON #workingtable(child)
/* insert yourself for a starting point */
insert into #workingtable (child,parent) --- set as parent
select top 1 @inputval,null
set @initval = @inputval
/*to include yourself in the loop as a starting point set this to 0 */
set @testval = 0
/* loop until all children has a parent as per relationship exists whether indirectly connected (half relative, step spouses) at least one connection*/
while (select count(1) from #workingtable where parent is null and child <> @testval) > 0
begin
/*so the loop can carry on include yourself now... later on the ctes will find your parents and kids*/
set @testval = @initval
/*get your parents and everyone above*/
;with mycteParent (child, parent)
as
(
select child,parent from #workingtable with (index([IDX_rel1]))
union all
select n.rel1 [child],n.rel2 [parent]
from #relationship n
inner join mycteParent c
on c.child = n.rel2
where not exists (select 1 from #workingtable x where x.parent = n.rel1) -- making sure it won't go infinite check if parent is already in the working table as parent
)
insert into #workingtable
select distinct child,parent
from mycteParent c
option (maxrecursion 0);
/*get your kids and everyone below*/
;with mycteChild (child, parent)
as
(
select child,parent from #workingtable with (index([IDX_rel1]))
union all
select n.rel2 [child],n.rel1 [parent]
from #relationship n
inner join mycteChild c
on c.child = n.rel1
where not exists (select * from #workingtable x where x.parent = n.rel2) -- making sure it won't go infinite check if parent is already in the working table as child
)
insert into #workingtable
select distinct child, parent
from mycteChild c
option (maxrecursion 0);
/* clean all nodes without parent but excluding yourself as the initial value*/
delete from #workingtable where parent is null and child <> @initval
/* get half relatives, these are people related to a child */
insert into #workingtable (child,parent)
select distinct n.rel1 ,null
from #relationship n
inner join #workingtable t
on t.child = n.rel2
where not exists ( select 1 from #workingtable t where n.rel1 = t.parent) -- making sure it's not already in the working table as a parent
and not exists ( select 1 from #workingtable t where n.rel1 = t.child) -- -- making sure it's not already in the working table as a child
end
/* merge and display unique nodes */
select child [myrelatives] from #workingtable
where child is not null
union
select parent from #workingtable
where parent is not null
order by child
drop table #workingtable
drop table #relationship
只想正确了解如何最好地构建 CTE。
我追求的是不分世代和后代的所有亲人
例如:
- Parents/Aunts/Uncles/,盛大Parents,盛大Parents
- 我的 Siblings/My Kids/My 侄子侄女
我可以弄清楚如何在之前或之后获取,但使用两个 CTE(递归)并可能使用临时 table 作为参考来获取 nieces/nephews 并将它们合并为 1 个结果。
还有其他利用递归 CTE 的选项吗?
如果你能引导我找到最好的想法或答案,我将不胜感激。
我在想"Get Parent"然后"Get Child",这个child有没有另一个parent(和之前的不一样),这个parent a child 然后循环返回。
下面是我的样本数据
预期结果:
上面是完美的树...但是如果有哪个 71 是我的 half-relative
60 | 70
60 | 71
61 | 71
62 | 72 -- where 72 is half-sibling of 70 and 62 is a new spouse
so the new expected result will be inclusive of 60, 70, 71, 72
不确定您要找什么。 我认为没有任何递归的必要。
仍然没有文本形式的真实数据。
declare @t table(rel1 int,rel2 int)
insert into @t values(70,80),(70,81),(80,90)
,(80,91),(81,810),(81,812),(91,100),(91,101)
,(91,102),(91,103),(91,104),(90,1020),(90,1030),(90,1040),(90,1010)
,(90,1050),(100,1020),(100,1030),(100,1040)
,(100,1050),(101,1001),(101,1002),(810,81001),(100,1010)
declare @input int=70
select t.rel1 from @t t
UNION
select t.rel2 from @t t
第二种方法,
select t.rel1 from @t t
inner join @t c
on t.rel2=c.rel1
union
select t.rel2 from @t t
inner join @t c
on t.rel1=c.rel2
Get Parent, Get Child, any Half relatives then Loop back approach
Recursive CTE and Loop
/* relatives table */
create table #relationship
(rel1 int,rel2 int)
insert into #relationship
values
(60,70),
(60,71),
(61,71),
(62,71), -- half relative ie. 62 as Step-spouse considered as extended family
(62,72), -- half relative ie. 72 as half-sibling of 71
(70,80),
(70,81)
,(80,90)
,(80,91)
,(81,810)
,(81,812)
,(91,100)
,(91,101)
,(91,102)
,(91,103)
,(91,104)
,(90,1020)
,(90,1030)
,(90,1040)
,(90,1010)
,(90,1050),
(100,1020),
(100,1030),
(100,1040)
,(100,1050)
,(101,1001)
,(101,1002)
,(101,2001)
,(810,81001)
,(100,1010)
/* you as 100 */
declare @inputval int = 100
/* need these variables for condition and switching values */
declare @initval int
declare @testval int
/* working table to get all child and parents and extended family */
create table #workingtable
(child int,
parent int
)
CREATE CLUSTERED INDEX IDX_rel1 ON #workingtable(child)
/* insert yourself for a starting point */
insert into #workingtable (child,parent) --- set as parent
select top 1 @inputval,null
set @initval = @inputval
/*to include yourself in the loop as a starting point set this to 0 */
set @testval = 0
/* loop until all children has a parent as per relationship exists whether indirectly connected (half relative, step spouses) at least one connection*/
while (select count(1) from #workingtable where parent is null and child <> @testval) > 0
begin
/*so the loop can carry on include yourself now... later on the ctes will find your parents and kids*/
set @testval = @initval
/*get your parents and everyone above*/
;with mycteParent (child, parent)
as
(
select child,parent from #workingtable with (index([IDX_rel1]))
union all
select n.rel1 [child],n.rel2 [parent]
from #relationship n
inner join mycteParent c
on c.child = n.rel2
where not exists (select 1 from #workingtable x where x.parent = n.rel1) -- making sure it won't go infinite check if parent is already in the working table as parent
)
insert into #workingtable
select distinct child,parent
from mycteParent c
option (maxrecursion 0);
/*get your kids and everyone below*/
;with mycteChild (child, parent)
as
(
select child,parent from #workingtable with (index([IDX_rel1]))
union all
select n.rel2 [child],n.rel1 [parent]
from #relationship n
inner join mycteChild c
on c.child = n.rel1
where not exists (select * from #workingtable x where x.parent = n.rel2) -- making sure it won't go infinite check if parent is already in the working table as child
)
insert into #workingtable
select distinct child, parent
from mycteChild c
option (maxrecursion 0);
/* clean all nodes without parent but excluding yourself as the initial value*/
delete from #workingtable where parent is null and child <> @initval
/* get half relatives, these are people related to a child */
insert into #workingtable (child,parent)
select distinct n.rel1 ,null
from #relationship n
inner join #workingtable t
on t.child = n.rel2
where not exists ( select 1 from #workingtable t where n.rel1 = t.parent) -- making sure it's not already in the working table as a parent
and not exists ( select 1 from #workingtable t where n.rel1 = t.child) -- -- making sure it's not already in the working table as a child
end
/* merge and display unique nodes */
select child [myrelatives] from #workingtable
where child is not null
union
select parent from #workingtable
where parent is not null
order by child
drop table #workingtable
drop table #relationship