无法在order by子句中的父记录之后获取子记录

时间:2013-08-27 19:56:36

标签: sql sql-server-2008

我有一个分类表和一个阶段表。每个类别都与某些阶段相关联,每个阶段可能有也可能没有子阶段。

这是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
  )

我正在尝试编写查询,以便按正确顺序获取Category,Stage和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

我缺少连接顺序的子句吗?

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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