在 SQL 服务器中显示排序的层次结构行?
Displaying sorted hierarchy rows in SQL server?
假设我有这个 table : ( c
是 parent p
的 child)
c p
------
40 0
2 3
2 40
3 1
7 2
1 0
其中(0
表示根)— 我希望 select 的顺序显示为:
c b
------
1 0
3 1
2 3
40 0
2 40
7 2
那是因为我们有 2 个根 (1,40) 并且 1 < 40。
所以我们从 1
开始,然后在它下面显示 - 所有它的后代。
然后我们到达 40
。同样的逻辑。
问题:
我该怎么做?
我已经成功地递归显示它+找到层次结构级别*(不确定是否有帮助)*
WITH cte(c, p) AS (
SELECT 40, 0 UNION ALL
SELECT 2,3 UNION ALL
SELECT 2,40 UNION ALL
SELECT 3,1 UNION ALL
SELECT 7,2 UNION ALL
SELECT 1,0
) , cte2 AS(
SELECT c,
p,
PLevel = 1
FROM cte
WHERE p = 0
UNION ALL
SELECT cte.c,
cte.p,
PLevel = cte2.PLevel + 1
FROM cte
INNER JOIN cte2
ON cte2.c = cte.p
)
SELECT *
FROM cte2
你差不多完成了。只需添加一个rank
来标识每个组,然后对它上面的数据进行排序。
此外,由于您正在处理更复杂的层次结构,我们需要更改 [level]
值。现在不是数字,将当前元素的完整路径放入其父元素。其中 \
表示父级。例如下面的字符串:
代表以下层级:
1
--> 5
--> 4
--> 1
我从 hierarchyid 类型中得到了这个想法。您可能需要考虑使用它来存储层次结构,因为它具有处理此类结构的便捷内置函数。
这是新数据的完整工作示例:
DECLARE @DataSource TABLE
(
[c] TINYINT
,[p] TINYINT
);
INSERT INTO @DataSource ([c], [p])
VALUES (1,0)
,(3, 1)
,(2, 3)
,(5,1)
,(7, 2)
,(40, 0)
,(2, 40);
WITH DataSource ([c], [p], [level], [rank])AS
(
SELECT [c]
,[p]
,CAST('/' AS VARCHAR(24))
,ROW_NUMBER() OVER (ORDER BY [c] ASC)
FROM @DataSource
WHERE [p] = 0
UNION ALL
SELECT DS.[c]
,DS.[p]
,CAST(DS1.[level] + CAST(DS.[c] AS VARCHAR(3)) + '/' AS VARCHAR(24))
,DS1.[rank]
FROM @DataSource DS
INNER JOIN DataSource DS1
ON DS1.[c] = DS.[p]
)
SELECT [c]
,[p]
FROM DataSource
ORDER BY [Rank]
,CAST([level] AS hierarchyid);
再次注意参与两个组的节点 (7,2)
(即使在您的示例中)。我想这只是一个示例数据,您可以通过一种方法来定义应包含节点的位置。
假设我有这个 table : ( c
是 parent p
的 child)
c p
------
40 0
2 3
2 40
3 1
7 2
1 0
其中(0
表示根)— 我希望 select 的顺序显示为:
c b
------
1 0
3 1
2 3
40 0
2 40
7 2
那是因为我们有 2 个根 (1,40) 并且 1 < 40。
所以我们从 1
开始,然后在它下面显示 - 所有它的后代。
然后我们到达 40
。同样的逻辑。
问题:
我该怎么做?
我已经成功地递归显示它+找到层次结构级别*(不确定是否有帮助)*
WITH cte(c, p) AS (
SELECT 40, 0 UNION ALL
SELECT 2,3 UNION ALL
SELECT 2,40 UNION ALL
SELECT 3,1 UNION ALL
SELECT 7,2 UNION ALL
SELECT 1,0
) , cte2 AS(
SELECT c,
p,
PLevel = 1
FROM cte
WHERE p = 0
UNION ALL
SELECT cte.c,
cte.p,
PLevel = cte2.PLevel + 1
FROM cte
INNER JOIN cte2
ON cte2.c = cte.p
)
SELECT *
FROM cte2
你差不多完成了。只需添加一个rank
来标识每个组,然后对它上面的数据进行排序。
此外,由于您正在处理更复杂的层次结构,我们需要更改 [level]
值。现在不是数字,将当前元素的完整路径放入其父元素。其中 \
表示父级。例如下面的字符串:
代表以下层级:
1
--> 5
--> 4
--> 1
我从 hierarchyid 类型中得到了这个想法。您可能需要考虑使用它来存储层次结构,因为它具有处理此类结构的便捷内置函数。
这是新数据的完整工作示例:
DECLARE @DataSource TABLE
(
[c] TINYINT
,[p] TINYINT
);
INSERT INTO @DataSource ([c], [p])
VALUES (1,0)
,(3, 1)
,(2, 3)
,(5,1)
,(7, 2)
,(40, 0)
,(2, 40);
WITH DataSource ([c], [p], [level], [rank])AS
(
SELECT [c]
,[p]
,CAST('/' AS VARCHAR(24))
,ROW_NUMBER() OVER (ORDER BY [c] ASC)
FROM @DataSource
WHERE [p] = 0
UNION ALL
SELECT DS.[c]
,DS.[p]
,CAST(DS1.[level] + CAST(DS.[c] AS VARCHAR(3)) + '/' AS VARCHAR(24))
,DS1.[rank]
FROM @DataSource DS
INNER JOIN DataSource DS1
ON DS1.[c] = DS.[p]
)
SELECT [c]
,[p]
FROM DataSource
ORDER BY [Rank]
,CAST([level] AS hierarchyid);
再次注意参与两个组的节点 (7,2)
(即使在您的示例中)。我想这只是一个示例数据,您可以通过一种方法来定义应包含节点的位置。