2012-03-31 10 views
2

Ich habe wieder mit rekursiven CTE zu kämpfen. Ich habe eine selbstreferenzierende Tabelle mit einer Punktzahl, die jeder Zeile zugeordnet ist. Ich muss die Sortierreihenfolge der Blattknoten nach Punktzahl auflösen, die der Sortierreihenfolge der Elternknoten entspricht (auch sortiert nach Punktzahl). Die Gruppierung sieht wie folgt aus:Ermitteln Sie die Rangfolge von Gruppen in einer selbstreferenzierenden Tabelle

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 

Dies ist das erwartete Ergebnis Satz:

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 

Hier Beispieldatensätze. Danke im Voraus.

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 

Antwort

2

EDIT: Basierend auf den Kommentaren unten scheint das Problem eher einfacher zu sein als ich dachte:

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

Ja, das merkt sich nicht die Partitur der Eltern. Es passiert einfach, in diesem Fall zu arbeiten, aber ändern Sie Group1 zu a.4 und es gibt immer noch die gleiche Ausgabe, wenn alles unter group1 bis zum Ende der Elternknoten fallen sollte: Dies kann hier gesehen werden. http://sqlfiddle.com/#!3/c0b64/2 Es überprüft im Grunde nur die maximale Punktzahl des unmittelbaren Elternteils, nicht nach oben –

+0

@JustinPihony - Tatsächlich verfolgt es die Ergebnisse. Ich bin nur ein wenig unklar darüber, was das OP wirklich will, indem es auf unberechenbare Weise sortiert. – HABO

+0

Die Sortierung ist nicht sprunghaft, sie basiert auf dem jeweils übergeordneten Element. Um zu versuchen, es besser zu erklären, sortiert er die oberen Eltern, dann sortiert er die Kinder, aber basiert auf dem obersten Elternteil (also ist es wie sagend, wenn parent1 die oberste Sortierung ist, dann haben ALLE ihre Kinder Vorrang vor JEDEM von parent2's Kinder) ... erklärt das das besser? –

2

So etwas sollte funktionieren. Die RIGHT ist sicher zu machen, wenn es eine 12 ist, dass die Reihenfolge 6 Ziffern bleibt oder es wird überlappen und versauen die nächste Rekursionstiefe

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

Danke Justin. Aber wie kann ich das Ranking auflösen? Ich habe es mit 'rank() über (nach Score desc) versucht', aber 'Gruppe iii' und 'Gruppe c' haben die selbe Punktzahl und ich lande mit doppelter Rangfolge. – Eric

+0

Ich vermute, es sollte im Set getan werden. In der prozeduralen Sprache wäre die Iteration wie folgt: alle Wurzelknoten nach Punktzahl sortieren Beschreibung >> alle untergeordneten Knoten in Gruppe 1 sortieren sortiert nach Punktzahl desc >> alle untergeordneten Knoten in Gruppe b nach Punktzahl desc> sortieren > rank alle Kinder und speichere .. – Eric

+0

@Eric Ich habe meine Antwort aktualisiert. Das erste sql ist genau das, was ich denke, das CTE sollte tun (aber nicht), und dann, wie man es über eine while-Schleife erreicht. Dies ist im Grunde tun, was der rekursive CTE hinter den Kulissen tun sollte. (Ich plane zu fragen, warum der CTE funktioniert so, wie ich es tue, da ich nicht damit einverstanden bin) –