【问题标题】:Get parents and children given a segment in a recursion SQL在递归 SQL 中获取给定段的父母和孩子
【发布时间】:2016-09-16 15:26:14
【问题描述】:

给定开头、中间或结尾的 ID,我想查找它们之间链接的所有行。

这样我递归地找到了子元素

declare @T table(
  Id int primary key,
  Name nvarchar(255) not null,
  ParentId int)

insert into @T values
(1,   'A',    NULL),
(2,   'B',    1),
(3,   'C',    2),
(4,   'D',    NULL),
(5,   'E',    1)

declare @Id int = 2

;with cte as
(  
  select T.*
  from @T as T
  where T.Id = @Id
  union all
  select T.*
  from @T as T
    inner join cte as C
      on T.ParentId = C.Id
)
select *
from cte 

如果@Id 等于 2,我将得到 2 和 3。但我也想检索父级,在本例中为 1。

我想得到这个:

如果 id = 1

1 A NULL
2 B 1
3 C 2
5 E 1

如果 id = 2

1 A NULL
2 B 1
3 C 2
5 E 1

如果 id = 3

1 A NULL
2 B 1
3 C 2
5 E 1

如果 id = 4

4 D NULL

如果 id = 5

1 A NULL
2 B 1
3 C 2
5 E 1

我该如何解决这个问题?

【问题讨论】:

  • 您可以编辑您的问题并添加所需的输出吗?
  • 为什么 id=1 我们不应该得到 '5 E 1' 记录?
  • 对不起,我的错。已更正。

标签: sql-server recursion parent-child nodes common-table-expression


【解决方案1】:

好的!我有你:

我创建了一个单独的家庭进行测试。

您需要做的第一件事是创建一个查询来查找您选择的 ID 的最古老的祖先。这是下面的第一个 CTE。然后你指定它,我称之为@Eve 并找到夏娃,夏娃的所有孩子。

Here is the example你可以玩弄

  create table UserType (
  Id int,
   name nvarchar(255),
  parentid int)

insert into UserType values
(1,  'A',    NULL),
(2,  'B',  1),
(3,  'C',   2),
(4,  'D',    NULL),
(5,  'E',   1),
(6,  'F',   NULL),
(7,  'G',      6),
(8,  'H',     7);

DECLARE @eve BIGINT;  --ancestor
DECLARE @id BIGINT;
SET @id = 8;  --This is where you choose

WITH tblParent AS  --CTE for oldest ancestor
(
    SELECT *
        FROM UserType WHERE Id = @id
    UNION ALL
    SELECT UserType.*
        FROM UserType  JOIN tblParent  ON UserType.Id = tblParent.ParentId
)
select
@eve = (select top 1 id from tblParent order by id);

WITH tblChild AS  --CTE for all @eve and all children
(
    SELECT *
        FROM UserType WHERE id = @eve
    UNION ALL
    SELECT UserType.* FROM UserType  JOIN tblChild  ON UserType.ParentId = tblChild.Id
)
SELECT * FROM tblChild
order by id


OPTION(MAXRECURSION 32767)

Props to CodeProject 很有帮助。

【讨论】:

  • 感谢您的回答。我更新了我的问题以显示我想要的输出。查询应该找到它们之间的所有链接。如果我更改 ID = 3 或 5,您的代码将不起作用
  • @MaximusDecimus 感谢您的评论,快速提问:您想要您声明的 ID 的父级和父级的所有后代吗?例如,5 岁的孩子为空,5 岁的父母为 1。但你想要 1 的所有孩子 (2) 和孙子 (3)?
  • 所有按 parentid 链接的行。祖父母,父母,孩子等等。所有相关行。我最多有 4 个级别,但如果我查找孙子,我将能够找到所有的孩子、父母和祖父母,以及所有与这些祖父母有关的人。
  • @MaximusDecimus 好的,所有相关行,可怜的孤独 Id = 4 :''(
【解决方案2】:

试试这样的。

declare  @tbl table( --test table var
Id int,
name nvarchar(255),
parentid int)

insert into @tbl values -- test data
(1,  'A',    NULL),
(2,  'B',  1),
(3,  'C',   2),
(4,  'D',    NULL),
(5,  'E',   1),
(6,  'F',   NULL),
(7,  'G',      6),
(8,  'H',     7);

declare @id int = 7

;with parents as (
select id,name,parentid, 0 lvl
from @tbl 
where id=@id
union all
select t.id,t.name,t.parentid,  lvl-1
from @tbl t
inner join parents p on t.Id=p.parentid --up the tree
)
,children as (
select id,name,parentid, 0 lvl
from @tbl 
where id=@id --select single record
union all
select t.id,t.name,t.parentid,  lvl+1
from @tbl t
inner join children c on c.Id=t.parentid -- down the tree
)
select * from parents
union --combine results
select * from children
order by lvl

【讨论】:

  • 非常感谢您的宝贵回答。当我搜索 2 或 3 时,我找不到数字 5。直接在 1 或 5 处。但是当我想要获取分支的所有链接行而不是表兄弟时,您的代码充当了另一种场景的模型!非常感谢。
猜你喜欢
  • 1970-01-01
  • 2013-06-04
  • 1970-01-01
  • 1970-01-01
  • 2015-08-30
  • 2021-06-29
  • 1970-01-01
  • 1970-01-01
  • 2020-07-22
相关资源
最近更新 更多