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
  )

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

join order by 句に欠けているものは何ですか?

4

2 に答える 2

2

最初は少し奇妙に思えるかもしれませんが、次のようになります。

  • Stages現在のステージの親を見つけるために、2 番目の左結合を行いました。
  • 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 に答える