查询以对分层数据进行分组和排序
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 级节点紧随其后,依此类推。
我的 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 级节点紧随其后,依此类推。