确定自引用表中组的排名

时间:2012-03-31 22:29:09

标签: sql sql-server-2008 data-structures hierarchical-data

我再次与递归CTE挣扎。我有一个自引用表,每行都有一个得分。我需要通过分数对应父节点的排序顺序(也按分数排序)来解析叶节点的排序顺序。分组看起来像这样:

Groups                  Score
------------------------------------
Group 1                 0.95
    Group a             0.7
        Group i         0.9
        Group ii        0.7
    Group b             0.9
        Group iii       0.5
        Group iv        1.0
Group 2                 0.9
    Group c             0.5
    Group d             0.8
Group 3                 1.0

这是预期的结果集:

GroupID     GroupName   Score   Rank
------------------------------------
11          Group 3     1.0     1
7           Group iv    1.0     2
6           Group iii   0.5     3
3           Group i     0.9     4
4           Group ii    0.7     5
10          Group d     0.8     6
9           Group c     0.5     7

这是示例记录。提前谢谢。

declare @tblGroups table (
            GroupID int,
            GroupName nvarchar(50),
            ParentID int,
            Score float
)

insert into @tblGroups values (1, 'Group 1', null, 0.95)
insert into @tblGroups values (2, 'Group a', 1, 0.7)
insert into @tblGroups values (3, 'Group i', 2, 0.9)
insert into @tblGroups values (4, 'Group ii', 2, 0.7)
insert into @tblGroups values (5, 'Group b', 1, 0.9)
insert into @tblGroups values (6, 'Group iii', 5, 0.5)
insert into @tblGroups values (7, 'Group iv', 5, 1.0)

insert into @tblGroups values (8, 'Group 2', null, 0.9)
insert into @tblGroups values (9, 'Group c', 8, 0.5)
insert into @tblGroups values (10, 'Group d', 8, 0.8)

insert into @tblGroups values (11, 'Group 3', null, 1.0)

select 
    g.* 
from 
    @tblGroups g

2 个答案:

答案 0 :(得分:2)

像这样的东西应该工作。 RIGHT是为了确定订单是否为6位数,否则它将重叠并弄乱下一个递归级别

WITH myCTE
AS
(
  SELECT *, ROW_NUMBER() OVER (ORDER BY Score desc) AS RowNumber, 
      RIGHT('000000' + CAST(ROW_NUMBER() OVER (ORDER BY Score desc) AS VARCHAR(MAX)),6) AS Overall
  FROM tblGroups
  WHERE ParentId IS NULL

  UNION ALL

  SELECT tblGroups.*, ROW_NUMBER() OVER (ORDER BY myCTE.RowNumber , tblGroups.Score desc) AS RowNumber,
       Overall + RIGHT('000000' + CAST(ROW_NUMBER() OVER (ORDER BY myCTE.RowNumber , tblGroups.Score desc) AS VARCHAR(MAX)),6) AS Overall
  FROM tblGroups
      JOIN myCTE
          ON myCTE.GroupID = tblGroups.ParentID
 )

SELECT *
FROM myCTE
          WHERE NOT EXISTS
      (
        SELECT 1
        FROM tblGroups AS ParentTbl
        WHERE myCTE.GroupID = ParentTbl.ParentID
      )
ORDER BY overall;

Here is the fiddle

答案 1 :(得分:2)

编辑:根据以下评论,问题似乎比我想象的要容易得多:

declare @tblGroups table ( GroupId int, GroupName nvarchar(50), ParentId int, Score float ) 
insert into @tblGroups values (1, 'Group 1', null, 0.95)    
insert into @tblGroups values (2, 'Group a', 1, 0.7)    
insert into @tblGroups values (3, 'Group i', 2, 0.9)    
insert into @tblGroups values (4, 'Group ii', 2, 0.7)    
insert into @tblGroups values (5, 'Group b', 1, 0.9)    
insert into @tblGroups values (6, 'Group iii', 5, 0.5)    
insert into @tblGroups values (7, 'Group iv', 5, 1.0)    

insert into @tblGroups values (8, 'Group 2', null, 0.9)    
insert into @tblGroups values (9, 'Group c', 8, 0.5)    
insert into @tblGroups values (10, 'Group d', 8, 0.8)    

insert into @tblGroups values (11, 'Group 3', null, 1.0)    

select * from @tblGroups

; with Greg as (
  -- The roots have no parents.
  select GroupId, GroupName, ParentId, Score,
    Cast( Right( '00000' + Cast( Row_Number() over ( order by Score desc ) as VarChar(6) ), 6 ) as VarChar(1024) ) as OverallRank
    from @tblGroups
    where ParentId is NULL
  union all
  -- Add the children one generation at a time.
  select T.GroupId, T.GroupName, T.ParentId, T.Score,
    Cast( G.OverallRank + Right( '00000' + Cast( Row_Number() over ( order by T.Score desc ) as VarChar(6) ), 6 ) as VarChar(1024) )
    from Greg as G inner join
      @tblGroups as T on T.ParentId = G.GroupId
  )
  select *
    from Greg as G
    where not exists ( select 42 from @tblGroups where ParentId = G.GroupId ) -- Leaf nodes only.
    order by OverallRank