查询以对分层数据进行分组和排序

Query to group and sort hierarchical data

我的 SQL Server 2008 中有一个这样的 table。

ID     ParentID    Level     Code    Name           Description
1      1           1         EXP     Expenses       --
2      1           2         PEXP    Project Exp    --
3      1           2         IEXP    Indirect Exp.  --
4      4           1         INC     Incomes        --
5      1           2         MEXP    Misc. Exp.     --
6      2           3         MCOST   Material Cost  --
7      4           2         IINC    Indirect Inc.  --
8      6           4         TCOS    Tiles Cost    --

我想要一个查询,其中 select 所有行都按层次顺序排列。 (Tiles Cost under Material Cost,Material Cost under Project Expense,Project Expenses under Expenses 等。最多可以有 5 个级别。table 中有 2000 行。)

这在 SQL 查询中可能吗?

预期结果应如下所示:

ID     ParentID    Level     Code    Name           Description
1      1           1         EXP     Expenses       --
3      1           2         IEXP    Indirect Exp.  --
5      1           2         MEXP    Misc. Exp.     --
2      1           2         PEXP    Project Exp    --
6      2           3         MCOST   Material Cost  --
8      6           4         TCOS    Tiles Cost    --
4      4           1         INC     Incomes        --
7      4           2         IINC    Indirect Inc.  --

基于您最多有 5 个级别这一事实,这应该可行。

如果您 select 只有第一层的值,然后使用内部联接向下层,您应该会得到预期的结果:

SELECT MyTable5.* FROM MyTable as MyTable1 
  INNER JOIN MyTable AS MyTable2 ON MyTable2.ParentId = MyTable1.Id
  INNER JOIN MyTable AS MyTable3 ON MyTable3.ParentId = MyTable2.Id
  INNER JOIN MyTable AS MyTable4 ON MyTable4.ParentId = MyTable3.Id
  INNER JOIN MyTable AS MyTable5 ON MyTable5.ParentId = MyTable4.Id
WHERE MyTable1.Level = 1
ORDER BY MyTable1.Id, MyTable5.Level

您可以使用 Recursive CTE :

;WITH CTE_Tree AS (
   -- Anchor member: get all parent nodes, initialize order_key
   SELECT ID, ParentID, Level, Code, Name, 
          CAST(ID AS VARCHAR(MAX)) AS order_key
   FROM mytable
   WHERE Level = 1

   UNION ALL

   -- Recursive member: get child node of previous node and update
   -- order _key of branch
   SELECT t1.ID, t1.ParentID, t1.Level, t1.Code, t1.Name,
          order_key = t2.order_key + '.' + CAST(t1.Level AS VARCHAR(MAX))
   FROM mytable AS t1
   INNER JOIN CTE_Tree AS t2 ON t1.ParentID = t2.ID AND t1.Level > t2.Level
)
SELECT *
FROM CTE_Tree
ORDER BY order_key,Code

CTE用于递归计算一个order key。 order key的第一位是父节点的ID。这是因为我们希望第一个父分支的所有节点都排在下一个父分支的节点之上。

第二,第三等,数字只是节点的级别。这样,2 级节点的顺序正好排在父节点之后,3 级节点紧随其后,依此类推。

Demo here