Определите ранжирование групп в таблице самоссылки - PullRequest
2 голосов
/ 01 апреля 2012

Я снова борюсь с рекурсивным 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 ]

2 голосов
/ 01 апреля 2012

РЕДАКТИРОВАТЬ: Исходя из комментариев ниже, кажется, что проблема гораздо проще, чем я думал:

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
2 голосов
/ 01 апреля 2012

Как-то так ДОЛЖНО работать. RIGHT должен убедиться, что если есть 12, то в ордере остаются 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;

Вот скрипка

...