0

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

  • 每个玩家必须通过外键属于一个团队TeamID
  • 每个团队可以通过递归字段属于另一个团队ParentTeamID

所以它可能是(自上而下)......

  • A队
  • B队
  • Team76
  • 组8
  • 播放器_ME

我的问题是,如果给我一个玩家PlayerID(那张桌子的 PK),那么获得顶级团队的最佳方式是什么?

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

WITH TeamTree
    AS (
        SELECT ParentTeam.*, Player.PlayerID, 0 as Level
        FROM Team ParentTeam
        INNER JOIN Player ON Player.TeamID = ParentTeam.TeamID
        WHERE Player.PlayerID IN (SELECT * FROM dbo.Split(@PlayerIDs,','))
        UNION ALL 
        SELECT ChildTeam.*, TeamTree.PlayerID AS PlayerID, TeamTree.Level + 1
        FROM Team ChildTeam
                INNER JOIN TeamTree TeamTree
        ON ChildTeam.TeamID = TeamTree.ParentTeamID
    )

现在虽然我认为这是开始的正确地方,但我认为可能有更好的方法。另外我有点卡住了!我尝试在连接中(在子查询中)使用 Level,但它没有用。

关于如何在树上工作并仅获得顶级细节的任何想法?

编辑:

ParentTeam 可以是 ParentTeam(无限递归),但 Player 只能属于一个 Team。

数据结构团队:TeamID (PK)、Name、ParentTeamID(递归字段)

玩家:PlayerID (PK)、姓名、TeamID (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”

4

2 回答 2

3

我相信这就是您正在寻找的东西,并免费提供了一些额外的信息 :-) Andrew 在他的编辑版本中有正确的想法,但我认为他的实现是不正确的。

架构和查询可在SQL Fiddle获得

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

编辑 - 回答评论中的问题

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

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
于 2012-07-16T19:47:02.537 回答
0
WITH TeamTree
    AS (
        SELECT ParentTeam.*, Player.PlayerID AS UrPlayerID, 0 as Level
        FROM Team ParentTeam
        INNER JOIN Player ON Player.TeamID = ParentTeam.TeamID
        WHERE Player.PlayerID IN (SELECT * FROM dbo.Split(@PlayerIDs,','))
        UNION ALL 
        SELECT ChildTeam.*, TeamTree.PlayerID AS PlayerID, TeamTree.Level + 1
        FROM Team ChildTeam
                INNER JOIN TeamTree TeamTree
        ON ChildTeam.ParentTeamID = TeamTree.TeamID /* These were reversed, I think */
           AND UrPlayerID=ChildTeam.PlayerID /* ADDED */
    )

否则你会得到大量重复的行,比如玩家数量的平方,不是吗?

- (在下面的评论之后)非常正确,我误读了架构。看,直到最后你都不需要把玩家带进来。我认为团队树的排列可能因玩家而异,但事实并非如此。所以

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;

Team如果您需要更多列,您可以重新加入。

于 2012-07-16T19:10:57.273 回答