SELECT for a Parent, Children and ORDER BY [Order] column

问题描述 投票:0回答:2

我在 SQL Server 中有一个表

myTable
如下所示:

身份证 父母身份 订单
1 1 1
2 2 1
3 3 1
4 1 2
5 1 1
6 1 3
7 4 1
8 2 2
9 2 1
100 3 1
10 10 1
194 10 1
295 194 1
205 194 2
215 194 3
322 10 2
404 10 3
435 10 4
507 10 5
206 10 6
330 10 7
425 10 8
428 10 9
488 10 10
432 10 11
633 10 12

我希望我的存储过程返回给定

ParentId
的输出,其中包含所有
Id
s 和他们的孩子按
Order
排序。

上表所需结果的示例:

测试

ParentId
= 1 应该返回:

身份证 父母身份 订单
1 1 1
5 1 1
4 1 2
7 4 1
6 1 3

Test

ParentId
= 4 应该返回 - 测试即使
Id
不是它自己的
ParentId
也会产生正确顺序的血统

身份证 父母身份 订单
4 1 2
7 4 1

测试

ParentId
= 2 应该返回:

身份证 父母身份 订单
2 2 1
9 2 1
8 2 2

测试

ParentId
= 3 应该返回:

身份证 父母身份 订单
3 3 1
100 3 1

测试

ParentId
= 10 应该返回(这是棘手的):

身份证 父母身份 订单
10 10 1
194 10 1
295 194 1
205 194 2
215 194 3
322 10 2
404 10 3
435 10 4
507 10 5
206 10 6
330 10 7
425 10 8
428 10 9
488 10 10
432 10 11
633 10 12

我已经设法使用以下代码获得给定

Id
ParentId
s,并且能够递归地对
Id
Id
的顺序进行排序:

DECLARE @myTable TABLE (Id INT, ParentID INT, [Order] INT)

INSERT INTO @myTable 
VALUES
(1,1,1),
(2,2,2),
(3,3,3),
(4,1,2),
(5,1,1),
(6,1,3),
(7,4,1),
(8,2,2),
(9,2,1),
(100,3,1),
(10,10,1),
(194,10,1),
(295,194,1),
(205,194,2),
(322,10,2),
(215,194,3),
(404,10,3),
(435,10,4),
(507,10,5),
(206,10,6),
(330,10,7),
(425,10,8),
(428,10,9),
(488,10,10),
(432,10,11),
(633,10,12)


IF OBJECT_ID(N'tempdb..#myTable') IS NOT NULL
BEGIN
    DROP TABLE #myTable
END

SELECT * 
INTO #myTable 
FROM @myTable;

WITH ChildHierarchy AS 
(
    -- Base query: find the direct children of the given ParentId
    SELECT 
        Id, ParentId, [Order], 0 AS HierarchyLevel, 
        CAST([Order] AS VARCHAR(MAX)) AS SortPath
    FROM 
        #myTable
    WHERE 
        ParentId = 1 AND Id != 1

    UNION ALL

    -- Recursive query: find the children of each child
    SELECT 
        O.Id, O.ParentId, O.[Order], HierarchyLevel + 1, 
        CAST(ChildHierarchy.SortPath + '.' + CAST(O.[Order] AS VARCHAR(MAX)) AS VARCHAR(MAX))
    FROM 
        #myTable O
    INNER JOIN 
        ChildHierarchy ON O.ParentId = ChildHierarchy.Id
)
SELECT * 
FROM 
    (SELECT 
         Id, ParentId, [Order], CAST(0 AS varchar) AS HierarchyLevel, 
         CAST(0 AS varchar) AS SortPath 
     FROM 
         #myTable 
     WHERE 
         Id = 1

     UNION
     
     SELECT * 
         FROM ChildHierarchy) AS X
     ORDER BY 
    [Order] ASC, X.SortPath ASC

除了测试

ParentId
= 10 之外,所有测试都产生写入顺序:

在@myTable

中,每行只会有一个层次结构(即,父母的孩子的孩子不会在另一列的一行中)

感谢任何帮助。

sql sql-server sorting parent-child
2个回答
1
投票

如果 SortPath 列的类型无关紧要,可以使用 varbinary 而不是 varchar。这将有助于正确排序。

DECLARE @root INT
SET @root = 10;

WITH ChildHierarchy AS 
(
    -- Base query: find the direct children of the given ParentId
    SELECT 
        Id, ParentId, [Order], 0 AS HierarchyLevel, 
        CAST([Order] AS VARBINARY(MAX)) AS SortPath
    FROM 
        #myTable
    WHERE 
        ParentId = @root AND Id != @root

    UNION ALL

    -- Recursive query: find the children of each child
    SELECT 
        O.Id, O.ParentId, O.[Order], HierarchyLevel + 1, 
        ChildHierarchy.SortPath + CAST(o.[Order] AS BINARY(2))
    FROM 
        #myTable O
    INNER JOIN 
        ChildHierarchy ON O.ParentId = ChildHierarchy.Id
)
SELECT * 
FROM 
    (SELECT * 
     FROM ChildHierarchy
     UNION
     SELECT 
         Id, ParentId, [Order], CAST(0 AS varchar) AS HierarchyLevel, 
         CAST(0 AS VARBINARY) AS SortPath 
     FROM 
         #myTable 
     WHERE 
         Id = @root) AS X
ORDER BY 
   X.[SortPath] ASC

结果会是这样的:


0
投票

你可以使用

hierarchyid
hierarchyid
就是为这种树形表设计的,允许按层次排序和查询。

您首先进行常规递归 CTE。将每个递归

[Order]
值连接在一起,由
/
分隔。然后简单地将最终结果转换为
hierarchyid
并按它排序。

WITH cte AS 
(
    SELECT 
      t.Id,
      t.ParentId,
      t.[Order],
      CONCAT('/', CAST([Order] AS varchar(8000)), '/') AS SortPath
    FROM #myTable t
    WHERE t.Id = 1

    UNION ALL

    SELECT 
      t.Id,
      t.ParentId,
      t.[Order],
      CONCAT(cte.SortPath, t.[Order], '/')
    FROM #myTable t
    INNER JOIN cte ON cte.Id = t.ParentId
      AND t.Id <> t.ParentId  -- remove root
)
SELECT
  Id,
  ParentId,
  [Order],
  SortPathId = CAST(SortPath AS hierarchyid)
FROM cte
ORDER BY 
  SortPathId;

db<>小提琴

我必须说,你目前的设计是有问题的。根值本身不应该有

ParentId
,而应该有
NULL
。这将消除对上面注释行的要求。

© www.soinside.com 2019 - 2024. All rights reserved.