我有一张如下表:

Id LinkSlug ParentPageId Order
1 home 0
2 page2 1
3 page3 2
4 page11 1 0
5 page12 1 1
6 page13 1 2
7 page21 2 0
8 page22 2 1
9 page121 5 0
10 page122 5 1
11 page123 5 2

我相信您已经看到了模式-每个Page可以有ParentPageId定义的任意数量的"子页面"

我一直在try 获取一个可以生成以下有序输出的查询(不使用LinkSlug个字母顺序,因为它们可以是任何内容):

Id LinkSlug ParentPageId Order
1 home 0
4 page11 1 0
5 page12 1 1
9 page121 5 0
10 page122 5 1
11 page123 5 2
6 page13 1 2
2 page2 1
7 page21 2 0
8 page22 2 1
3 page3 2

我try 了一些自连接和分组,但最终只有一级递归,因此对第三级和可能的第n级子页没有好处,然后还try 使用CTE,因为我知道它们对递归查询很好,但不知何故最终生成了我开始使用的同一个表,现在不知所措!

我越是try ,情况就越糟-我知道我需要有效地 Select 按[顺序]排序的顶层(ParentPageId为null),然后在有子页按[顺序]排序的地方注入,并重复操作,直到没有子页-但不知道如何在SQL中做到这一点.

View on DB Fiddle

这是提琴脚本以防万一:

CREATE TABLE [Pages](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [LinkSlug] [nvarchar](450) NOT NULL,
    [ParentPageId] [int] NULL,
    [Order] [int] NOT NULL
);

INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (1, 'home', NULL, 0);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (2, 'page2', NULL, 1);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (3, 'page3', NULL, 2);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (4, 'page11', 1, 0);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (5, 'page12', 1, 1);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (6, 'page13', 1, 2);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (7, 'page21', 2, 0);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (8, 'page22', 2, 1);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (9, 'page121', 5, 0);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (10, 'page122', 5, 1);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (11, 'page123', 5, 2);

推荐答案

您需要一个递归的CTE来构建层次 struct 和维护序列

Example

with cte1 as (
      Select [Id]
            ,[LinkSlug]
            ,[ParentPageId]
            ,[Order]
            ,Seq  = cast(10000+Row_Number() over (Order by [Order]) as varchar(500))
      From   pages
      Where  [ParentPageId] is null
      Union  All
      Select cte2.[Id]
            ,cte2.[LinkSlug]
            ,cte2.[ParentPageId]
            ,cte2.[Order]
            ,Seq  = cast(concat(cte1.Seq,'.',10000+Row_Number() over (Order by cte2.[Order])) as varchar(500))
      From   pages cte2 
      Join   cte1 on cte2.[ParentPageId] = cte1.[Id])
Select *
 From cte1
 Order By Seq

Results

enter image description here

Sql相关问答推荐

神秘的日期转换

使用自动增量ID插入失败(无法将值空插入列ID)

如何将varchar传递给tvf并使用该参数来查询结果SQL服务器

使用交叉应用透视表在SQL中转换分段时间段&

Trino/Presto sq:仅当空值位于组中第一个非空值之后时,才用值替换空值

通过 Select 值的顺序进行排序ClickHouse

Lag()函数的差异:R与SQL(将R代码转换为SQL)

如何用QuestDB生成蜡烛图?

基于另一个(SAS、SQL)中的值更新列

如何为缺少的类别添加行

更正用于判断错误组合的SQL

在SQL中将项分配给容器

同时插入和更新记录

在SQL中转换差异表的多列

如何在 SQL Server 中解决这个复杂的窗口查询?

如何根据 Google BigQuery 中的特定列值连接一列的 N 行?

Postgresql:在链接表中判断相关表中插入值的条件

PostgreSQL分割字符串为子词并判断其是否存在于其他字符串中

每组使用平均值来填补缺失值的SQL

Select 字段,除非另一个字段包含重复项