Sql 将递归限制到某个级别

Sql 将递归限制到某个级别,sql,sql-server,sql-server-2008,recursion,Sql,Sql Server,Sql Server 2008,Recursion,我有一个名为Player的SQL表和另一个名为Team的SQL表 每个玩家必须通过外键TeamID属于一个团队 通过递归字段ParentTeamID,每个团队可以属于另一个团队 所以它可能是(自上而下) TeamA 团队B 76队 第8组 我的球员 我的问题是,如果给我一个球员的PlayerID(该表的PK),那么获得顶级球队的最佳方式是什么 到目前为止我的查询(得到所有团队): 现在,虽然我认为这是一个正确的开始,但我认为可能有更好的方法。而且我有点被卡住了!我尝试在连接中使用Leve

我有一个名为Player的SQL表和另一个名为Team的SQL表

  • 每个玩家必须通过外键
    TeamID
    属于一个团队
  • 通过递归字段
    ParentTeamID
    ,每个团队可以属于另一个团队
所以它可能是(自上而下)

  • TeamA
  • 团队B
  • 76队
  • 第8组
  • 我的球员
我的问题是,如果给我一个球员的
PlayerID
(该表的PK),那么获得顶级球队的最佳方式是什么

到目前为止我的查询(得到所有团队):

现在,虽然我认为这是一个正确的开始,但我认为可能有更好的方法。而且我有点被卡住了!我尝试在连接中使用Level(在子查询中),但没有成功

有没有关于如何在树上工作,只获取顶层细节的想法

编辑:

父团队可以是父团队(无限递归),但玩家只能属于一个团队

数据结构 小组: TeamID(主键)、名称、ParentTeamID(递归字段)

玩家: 玩家ID(主键)、姓名、团队ID(FK)

样本数据:

Team:
1, TeamA, NULL
2, TeamB, 1
3, Team76, 2
4, Group8, 3

Player:
1, Player_ME, 4
2, Player_TWO, 2
因此,有了上述数据,两个玩家都应该(在查询中)显示他们有一个TeamA的“TopLevelTeam”

否则你会得到一个巨大的重复行,类似于玩家数量的平方,不是吗

-- (以下评论后) 完全正确,我误读了模式。听着,你不需要把球员带到最后。我认为球队树的安排可能因球员而异,但事实并非如此。所以

WITH recursive TeamTree AS (
   SELECT TeamID, ParentTeamID FROM Team T1
   UNION ALL
   SELECT T1.TeamID, T2.ParentTeamID FROM T1 JOIN T2 ON T1.ParentTeamID=T2.TeamID
   )
 SELECT TeamTree.* FROM TeamTree JOIN Team T3 
      ON TeamTree.ParentTeamID=T3.TeamID WHERE T3.ParentTeamID IS NULL;
这将为您提供每个团队及其根祖先的表。现在将其加入玩家表

SELECT * FROM Player JOIN  (WITH TeamTree AS (
       SELECT TeamID, ParentTeamID FROM Team T1
       UNION ALL
       SELECT T1.TeamID, T2.ParentTeamID FROM T1 JOIN T2 ON T1.ParentTeamID=T2.TeamID
       )
     SELECT TeamTree.* FROM TeamTree JOIN Team T3 
          ON TeamTree.ParentTeamID=T3.TeamID WHERE T3.ParentTeamID IS NULL) teamtree2
     ON Player.TeamID=teamtree2.TeamID;
如果需要更多列,您可以重新加入
团队

否则你会得到一个巨大的重复行,类似于玩家数量的平方,不是吗

-- (以下评论后) 完全正确,我误读了模式。听着,你不需要把球员带到最后。我认为球队树的安排可能因球员而异,但事实并非如此。所以

WITH recursive TeamTree AS (
   SELECT TeamID, ParentTeamID FROM Team T1
   UNION ALL
   SELECT T1.TeamID, T2.ParentTeamID FROM T1 JOIN T2 ON T1.ParentTeamID=T2.TeamID
   )
 SELECT TeamTree.* FROM TeamTree JOIN Team T3 
      ON TeamTree.ParentTeamID=T3.TeamID WHERE T3.ParentTeamID IS NULL;
这将为您提供每个团队及其根祖先的表。现在将其加入玩家表

SELECT * FROM Player JOIN  (WITH TeamTree AS (
       SELECT TeamID, ParentTeamID FROM Team T1
       UNION ALL
       SELECT T1.TeamID, T2.ParentTeamID FROM T1 JOIN T2 ON T1.ParentTeamID=T2.TeamID
       )
     SELECT TeamTree.* FROM TeamTree JOIN Team T3 
          ON TeamTree.ParentTeamID=T3.TeamID WHERE T3.ParentTeamID IS NULL) teamtree2
     ON Player.TeamID=teamtree2.TeamID;

如果您需要更多专栏,您可以重新加入
团队。

我相信这就是您想要的,免费提供一些额外信息:-) 安德鲁在他编辑的版本中有正确的想法,但我认为他的实现是不正确的

架构和查询可在

编辑-回答评论中的问题

只需第二次加入CTE,您就可以导航到玩家团队层级中的任何级别。在你的情况下,你要求的是排名第二的团队:


我相信这就是你要找的,免费提供一些额外的信息:-) 安德鲁在他编辑的版本中有正确的想法,但我认为他的实现是不正确的

架构和查询可在

编辑-回答评论中的问题

只需第二次加入CTE,您就可以导航到玩家团队层级中的任何级别。在你的情况下,你要求的是排名第二的团队:



顶级团队是什么意思?你能展示几行样本数据并展示你想要的结果吗?那么你是说你目前的方法有效吗?团队的深度如何?家长可以有家长吗?@AaronBertrand我已经修改了我的问题,加入了结构和样本数据。@AbeMiessler不,我当前的方法显示了一名球员所属的所有球队,但我只想要最顶端的一支(带有“NULL”ParentTeamID的球队)。top team
是什么意思?你能展示几行样本数据并展示你想要的结果吗?那么你是说你目前的方法有效吗?团队的深度如何?家长可以有家长吗?@AaronBertrand我已经修改了我的问题,加入了结构和样本数据。@AbeMiessler不,我当前的方法显示了一名球员所属的所有球队,但我只想要最顶端的一支(带有“NULL”ParentTeamID的球队)和UrPlayerID=ChildTeam.PlayerID/*ADDED*/“部分是错误的,因为没有相等项,但即使有了这条线(或者根本没有这条线),我还是得到了更低的单位。因此,在您的示例中(使用我的数据),查看玩家“player_ME”会返回“Group8”,这是最低的团队(就在玩家的正上方)。。。我需要它返回“TeamA”。不幸的是,我得到的多部分标识符T1无法绑定到这一行“SELECT T1.TeamID,T2.ParentTeamID FROM T1 JOIN T2 on T1.ParentTeamID=T2.TeamID”我已经试着填空,但我想不出来……请尝试从TeamTree T1 JOIN T2中选择
。不幸的是,我没有从办公室很好地访问数据库,而且我很难记住递归查询的语法。谢谢你的帮助,但是dbbenham有一个稍微不同的解决方案,我将使用它。再次感谢你!:)“AND UrPlayerID=ChildTeam.PlayerID/*ADDED*/”部分是一个错误,因为没有相等项,但即使有这条线(或者根本没有这条线),我也得到了较低的单位。因此,在您的示例中(使用我的数据),查看玩家“player_ME”会返回“Group8”,这是最低的团队(就在玩家的正上方)。。。我需要它返回“TeamA”。不幸的是,我得到的多部分标识符T1无法绑定到这一行“SELECT T1.TeamID,T2.ParentTeamID FROM T1 JOIN T2 on T1.ParentTeamID=T2.TeamID”我已经试着填空,但我想不出来……请尝试从TeamTree T1 JOIN T2中选择
。不幸的是,我没有从办公室很好地访问数据库,而且我很难记住递归查询的语法。谢谢你的帮助,但是dbbenham有一个稍微不同的解决方案,我将使用它。再次感谢你!:)啊,你从最高层开始工作,然后一直工作到球员的团队。真是妙不可言!起初我还以为是巫毒呢!:)还有一个简单的问题——如果我想获得排名第二的顶级单位,我会怎么做?(仍然是问题标题的一部分)
with teamCTE as (
  select TeamID,
         TeamName,
         cast(null as int) as ParentTeamID,
         cast(null as varchar(10)) as ParentTeamName,
         TeamID TopTeamID,
         TeamName TopTeamName,
         1 as TeamLevel
    from team
   where ParentTeamID is null
  union all
  select t.TeamID,
         t.TeamName,
         c.TeamID,
         c.TeamName,
         c.TopTeamID,
         c.TopTeamName,
         TeamLevel+1 as TeamLevel
    from team t
    join teamCTE c
      on t.ParentTeamID = c.TeamID
)
select p.PlayerID,
       p.PlayerName,
       t.*
  from player p
  join teamCTE t
    on p.TeamID = t.TeamID
with teamCTE as (
  select TeamID,
         TeamName,
         cast(null as int) as ParentTeamID,
         cast(null as varchar(10)) as ParentTeamName,
         TeamID TopTeamID,
         TeamName TopTeamName,
         1 as TeamLevel
    from team
   where ParentTeamID is null
  union all
  select t.TeamID,
         t.TeamName,
         c.TeamID,
         c.TeamName,
         c.TopTeamID,
         c.TopTeamName,
         TeamLevel+1 as TeamLevel
    from team t
    join teamCTE c
      on t.ParentTeamID = c.TeamID
)
select p.PlayerID,
       p.PlayerName,
       t1.*,
       t2.TeamID Level2TeamID,
       t2.TeamName Level2TeamName
  from player p
  join teamCTE t1
    on p.TeamID = t1.TeamID
  join teamCTE t2
    on t1.TopTeamID = t2.TopTeamID
   and t2.TeamLevel=2