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

我错过了什么 join order by 子句?

4

2 回答 2

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

于 2013-08-27T20:10:05.700 回答
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
于 2013-08-27T20:15:33.007 回答