2012-03-31 9 views
2

私は再帰的な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

編集:以下のコメントに基づいて問題は思ったよりもずっと簡単だと思われます:

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 
+0

これは、親のスコアのすべての方法を追跡することはありません。この場合はうまくいくでしょうが、Group1を.4に変更すると、group1の下のすべてが親ノードの一番下に落ちるときにも、同じ出力が得られます。 http://sqlfiddle.com/#!3/c0b64/2それは基本的に、直接の親の最大スコアをチェックするだけで、トップへ伝えません。 –

+0

@JustinPihony - 実際にはスコアを記録します。私はOPが本当に望んでいないものを並べ替える方法で本当に望んでいるかどうか少し不明です。 – HABO

+0

並べ替えは不規則ではなく、それぞれの親に基づいています。それをよりうまく説明しようとすると、親をソートしていますが、子をソートしますが、親の親をベースにしています(parent1が一番上のソートの場合は、すべての子が親2の子供たち)...それはそれをより良く説明しますか? –

2

これは次のようなものです。そこ注文は6桁のまま12であるか、そうでなければオーバーラップすると場合RIGHTは確認することです台無し次の再帰レベル

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

+0

ありがとうございました。しかし、私はどのようにランキングを解決するのですか?私は 'rank()over(score desc)'でそれを試しましたが、 'Group iii'と 'Group c'は同じスコアを持ち、重複ランキングになります。 – Eric

+0

私はそれがセットで行われるべきだと思います。手続き型言語を使用すると、反復は次のようになります:スコアdescでソートされたすべてのルートノードを取得>>スコア1でグループ化されたすべての子ノードを取得>> group bですべての子ノードを取得desc desc> >すべての子どもをランク付けして保存します。 – Eric

+0

@Eric私は自分の答えを更新しました。最初のSQLは、CTEがすべきだと思うものですが、whileループを介してそれを達成する方法はありません。これは基本的に再帰的なCTEが背後で何をしているべきかを実行しています。 (私はCTEがなぜそれに同意しないのかということを尋ねる予定です) –