2013-08-27 35 views
2

我有一個類別表和一個階段表。每個類別都與一些階段相關聯,每個階段可能有也可能沒有子階段。無法獲得父記錄後按子句排序的子記錄

這是SQL架構的樣子:

CREATE TABLE Category 
    (
    Id BIGINT, 
    Name VARCHAR(100), 
    Ordinal BIGINT 
) 


CREATE TABLE Stages 
    (
    Id BIGINT, 
    Name VARCHAR(100), 
    CategoryId BIGINT, 
    ParentStage BIGINT, 
    Ordinal BIGINT 
) 

我想寫的查詢,使我得到類別,舞臺和ChildStages以正確的順序。

這是我想獲得:

Category    Stage 
----------------------------- 
Cat1    Cat1Stage1 
Cat1    Cat1Stage2 
Cat1    Cat1Stage3 
Cat1    Cat1Stage3ChildStage1 
Cat1    Cat1Stage3ChildStage2 
Cat1    Cat1Stage3ChildStage3 
Cat1    Cat1Stage4 
Cat1    Cat1Stage5 

Cat2    Cat2Stage1 
Cat2    Cat2Stage2 
Cat2    Cat2Stage3 
Cat2    Cat2Stage3ChildStage1 
Cat2    Cat2Stage3ChildStage2 
Cat2    Cat2Stage3ChildStage3 
Cat2    Cat2Stage4 
Cat2    Cat2Stage5 

這是查詢我寫這並沒有給我結果的順序:

SELECT Category.Name 'Category Name', 
     Stages.Name 'Stage Name' 
    FROM Category 
    LEFT JOIN Stages 
     ON Category.Id = Stages.CategoryId 
    ORDER BY Category.Ordinal, 
     CASE WHEN ParentStage IS NULL THEN Stages.Ordinal ELSE ParentStage END 

http://sqlfiddle.com/#!3/d8c2d

什麼我錯過了連接順序的子句嗎?

+0

如果您'ORDER BY Category.Ordinal,Stages.Name' - 會不會給你你需要的東西? –

+0

是否會有超過1級的兒童階段?如果是這樣,那麼您需要遞歸查詢來構建正確的排序鍵。 – David

回答

2

最初,這可能看起來有點不可思議,但在這裏有雲:

  • 我做了第二次左連接到Stages查找當前階段的家長。
  • order by子句包含:
    • 第一Category.Ordinal,如查詢
    • 其次:
      • 如果當前階段不是另一個孩子:Stage.Ordinal乘以某個任意大數(在我的情況下爲1000)
      • 否則,父階段的序數*任意大數目+當前階段的序數。

這確保了一個父階段之後緊接着其子,前提是有與多個孩子比任意選擇的大量的大無階段。

所以,這裏的查詢看起來像:

SELECT c.Name 'Category Name', 
     s.Name 'Stage Name' 
FROM Category c 
LEFT JOIN Stages s 
    ON c.Id = s.CategoryId 
left join Stages ps 
    on s.ParentStage = ps.Id 
ORDER BY c.Ordinal, 
case 
    when ps.Id is null then s.Ordinal * 1000 
    else ps.Ordinal * 1000 + s.Ordinal 
end 

而這裏的演示:http://sqlfiddle.com/#!3/d8c2d/27

2

下面一個使用在遞歸CTE路徑計算的傳統做法:

;WITH cteStages AS(
    SELECT *, 
     Path=cast(row_number() over (partition by ParentStage order by Ordinal) as varbinary(max)) 
    FROM Stages 
    WHERE ParentStage is null 
    UNION ALL 
    SELECT s.*, 
     c.Path + cast(row_number() over (partition by s.ParentStage order by s.Ordinal) as binary(8)) 
    FROM Stages s 
     JOIN cteStages c ON s.ParentStage = c.Id 
) 
SELECT c.Name [Category Name], s.Name [Stage Name] 
    FROM Category c 
    JOIN cteStages s ON c.Id = s.CategoryId 
    ORDER BY c.Ordinal, s.Path