2

首先,这不是我的另一个同名问题的重复,我只是想不出一个更好的名字!

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

  • 每个玩家必须通过外键 UnitID 属于一个团队。
  • 每个单元可以通过递归字段 ParentUnitID 属于另一个团队。
  • ParentUnit 可以是 ParentUnit(无限递归),但 Player 只能属于一个 Team。
  • 一个单元可能有很多孩子

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

  • TeamA(是顶级)
  • TeamB (属于^^)
  • TeamC (属于^^)
  • TeamD (属于^^)
  • Player_1 (属于^^)

我的问题是,如果给我一个 Player's PlayerID(该表的 PK),那么获得特定团队的最佳方法是什么?

有关数据、结构和查询,请参阅我的 SQLFiddle:http ://sqlfiddle.com/#!3/78965/3

使用我的数据(来自小提琴),我希望能够让每个玩家都在“TeamB”之下,但是“Player4”的顶级单位应该是“TeamC”。为此,我只想传入 PlayerID 和“TeamB”的 ID。所以我的意思是“让 TeamB 下的所有玩家和顶级单位,然后过滤掉除 Player4 之外的所有玩家。

编辑:我相信上面的段落应该是: 使用我的数据(来自小提琴),我希望能够建立在“TeamB”之下比赛的顶级球队。然后,对于“TeamB”以下的每个顶级球队,我想建立所有为该球队效力或低于该球队的球员。然后,我希望能够将玩家列表限制为一个或多个特定玩家。

正如您在 SQLFiddle 中看到的那样,我为每个玩家返回了多行,我确定这是一个快速修复,但我无法弄清楚......这就是我在小提琴中想要的,但它是,好吧,呃,有点繁琐... :)

编辑:更多信息:

好的,所以如果想象这是一个存储过程。

  • 我传入 PlayerIDs 1,2,3,4
  • 我传入 UnitID 2

我希望返回的数据看起来像

Player3, TeamC

仅返回 Player3,因为它是 TeamB (ID 2) 的唯一后代玩家,返回 TeamC,因为它是 Player3 所属的最高级别单元 (UnitID 2 以下)。

如果我改为通过:

  • 我传入 PlayerIDs 1,2,3,4
  • 我传入 UnitID 6

我希望

Player1, Team2
Player2, Team2
4

2 回答 2

2
with UnitCTE as (
  select UnitID,
         Designation,
         ParentUnitID as ParentUnitID,
         cast(null as varchar(50)) as ParentUnitDesignation,
         UnitID TopUnitID,
         Designation TopUnitDesignation,
         1 as TeamLevel
    from Unit
   where ParentUnitID is null
  union all
  select t.UnitID,
         t.Designation,
         c.UnitID,
         c.Designation,
         c.TopUnitID,
         c.TopUnitDesignation,
         TeamLevel+1 as TeamLevel
    from Unit t
    join UnitCTE c
      on t.ParentUnitID = c.UnitID
      --WHERE t.UnitID = 1
),
x AS (
select Player.PlayerID,
       pDesignation = Player.Designation, t1.*,
       rn = ROW_NUMBER() OVER (PARTITION BY Player.PlayerID ORDER BY Player.Designation)
  from Player
  join UnitCTE t1
    on Player.UnitID = t1.UnitID
  join UnitCTE t2
    on t1.TopUnitID = t2.TopUnitID
   and t2.TeamLevel=2
)
SELECT * FROM x
WHERE rn = 1
   ORDER BY TeamLevel
于 2012-07-16T21:36:09.483 回答
2

这个答案已被完全重写。原版在所有情况下都无法正常工作

我必须更改 CTE 以将每个单元的完整单元层次结构表示为可能的根(顶部单元)。它允许一个真正的层次结构,每个单元有多个子级。

我扩展了此SQL Fiddle中的示例数据,将一名球员分配给了第 11 和第 12 单元。它正确地为在第 1 单元下方某个级别上为某个单位效力的 3 名球员中的每一位返回正确的行。

“根”单元 ID 和玩家 ID 列表方便地位于底部最外层的 WHERE 子句中,可以根据需要轻松更改 ID。

with UnitCTE as (
  select u.UnitID,
         u.Designation UnitDesignation,
         u.ParentUnitID as ParentUnitID,
         p.Designation as ParentUnitDesignation,
         u.UnitID TopUnitID,
         u.Designation TopUnitDesignation,
         1 as TeamLevel
    from Unit u
    left outer join Unit p
      on u.ParentUnitId = p.UnitID
  union all
  select t.UnitID,
         t.Designation UnitDesignation,
         c.UnitID as ParentUnitID,
         c.UnitDesignation as ParentUnitDesignation,
         c.TopUnitID,
         c.TopUnitDesignation,
         TeamLevel+1 as TeamLevel
    from Unit t
    join UnitCTE c
      on t.ParentUnitID = c.UnitID
)
select p.PlayerID,
       p.Designation,
       t1.*
  from UnitCTE t1
  join UnitCTE t2
    on t2.TopUnitID = t1.UnitID
   and t2.TopUnitID = t1.TopUnitID
  join Player p
    on p.UnitID = t2.UnitID
 where t1.ParentUnitID = 1
   and playerID in (1,2,3,4,5,6)

这是一个略微优化的版本,它在 CTE 中嵌入了 Unit ID 标准。CTE 仅计算以父 ID 为所选单元 ID(在本例中为 1)的单元为根的层次结构

with UnitCTE as (
  select u.UnitID,
         u.Designation UnitDesignation,
         u.ParentUnitID as ParentUnitID,
         p.Designation as ParentUnitDesignation,
         u.UnitID TopUnitID,
         u.Designation TopUnitDesignation,
         1 as TeamLevel
    from Unit u
    left outer join Unit p
      on u.ParentUnitId = p.UnitID
   where u.ParentUnitID = 1
  union all
  select t.UnitID,
         t.Designation UnitDesignation,
         c.UnitID as ParentUnitID,
         c.UnitDesignation as ParentUnitDesignation,
         c.TopUnitID,
         c.TopUnitDesignation,
         TeamLevel+1 as TeamLevel
    from Unit t
    join UnitCTE c
      on t.ParentUnitID = c.UnitID
)
select p.PlayerID,
       p.Designation,
       t1.*
  from UnitCTE t1
  join UnitCTE t2
    on t2.TopUnitID = t1.UnitID
  join Player p
    on p.UnitID = t2.UnitID
 where playerID in (1,2,3,4,5,6)



这是我的原始答案。 它仅在单元层次结构被限制为每个单元只允许一个孩子时才有效。问题中的 SQL Fiddle 示例有 Unit 1 的 3 个子项,因此如果针对 Unit 1 运行,它会错误地为玩家 3、5 和 6 返回多行

这是一个演示问题的SQL Fiddle

with UnitCTE as
  select UnitID,
         Designation UnitDesignation,
         ParentUnitID as ParentUnitID,
         cast(null as varchar(50)) as ParentUnitDesignation,
         UnitID TopUnitID,
         Designation TopUnitDesignation,
         1 as TeamLevel
    from Unit
   where ParentUnitID is null
  union all
  select t.UnitID,
         t.Designation UnitDesignation,
         c.UnitID,
         c.UnitDesignation,
         c.TopUnitID,
         c.TopUnitDesignation,
         TeamLevel+1 as TeamLevel
    from Unit t
    join UnitCTE c
      on t.ParentUnitID = c.UnitID
)
select p.PlayerID,
       p.Designation,
       t2.*
  from Player p
  join UnitCTE t1
    on p.UnitID = t1.UnitID
  join UnitCTE t2
    on t2.TopUnitID = t1.TopUnitID
   and t1.TeamLevel >= t2.TeamLevel
  join UnitCTE t3
    on t3.TopUnitID = t1.TopUnitID
   and t2.TeamLevel = t3.TeamLevel+1
 where t3.UnitID = 2
   and playerID in (1,2,3,4)
于 2012-07-16T22:41:09.343 回答