T-SQL 仅按 parent 级别排序的递归查询
T-SQL recursive query that sorts by parent level only
我正在尝试实现以下要求:
我有一个产品及其备件的层次结构。这些备件可以在图表中包含其他部分,这些部分可能具有几层深度。
我的目标是编写一个 T-SQL 查询,允许我按 table 的任何列(在示例产品、价格或 EndOfWarrantyDate 中)进行排序,但保留层次结构。换句话说,我只想订购 parent 项,而不用担心应该只在 parent 之后发挥作用的 children .
在下面的示例中,如果您注意到,绿色行按“EndOfWarrantyDate”排序,但我仍想在 parent 旁边显示 children 和 sub-children (我不关心订购 children,只要尊重层次结构即可)。
注意:上面table中的Id只是为了更好地识别层次结构,在数据库中我有一个普通的标识列作为Id。
而且,如果可能的话,我想在单个 SQL 查询中执行此操作,而不必先收集 parent 项,订购它们,然后获取相关的 children 和子children.
目前我的CTE是这样的,但是我不知道如何实现排序。尝试使用分区,但不知道如何正确应用它来解决我的问题。
WITH
cteProducts (Id, Product, ParentProductId, Price, EndOfWarrantyDate, Depth, RootId)
AS
(
-->>>>>>>>>>Root>>>>>>>>>>>>>>>>>
SELECT Id, Product, ParentProductId, Price, EndOfWarrantyDate, 0 as Depth, Id as RootId
FROM Products
WHERE ParentProductId IS NULL
-->>>>>>>>>>Root>>>>>>>>>>>>>>>>>
UNION ALL
-->>>>>>>>>>Children>>>>>>>>>>>>>>>>>
SELECT e.Id, e.Product, e.ParentProductId, e.Price, e.EndOfWarrantyDate, r.Depth + 1, r.RootId
FROM Products e
INNER JOIN cteProducts r
ON e.ParentProductId = r.Id
-->>>>>>>>>>Children>>>>>>>>>>>>>>>>>
)
SELECT
Id, Product, ParentProductId, Price, EndOfWarrantyDate, Depth, RootId
FROM cteProducts
--ORDER BY RootId, EndOfWarrantyDate
非常感谢任何帮助,谢谢!
保留父 EndOfWarrantyDate
作为递归 CTE 的一部分。这样最后就可以排序了
示例数据
declare @Products table
(
Id nvarchar(10),
Product nvarchar(20),
ParentProductId nvarchar(10),
Price int,
EndOfWarrantyDate date
);
insert into @Products (Id, Product, ParentProductId, Price, EndOfWarrantyDate) values
('1', 'Vacuum', null, 130, '2013-04-02'),
('1.1', 'Power Unit', '1', 200, '2024-01-01'),
('1.1.1', 'Unit part', '1.1', 100, '2024-01-01'),
('1.2', 'Filter', '1', 10, '2022-07-15'),
('2', 'Laptop', null, 600, '2023-06-01'),
('2.1', 'Hard Disk', '2', 200, '2024-03-01'),
('3', 'Washing Machine', null, 1000, '2023-12-01');
解决方案
WITH
cteProducts (Id, Product, ParentProductId, Price, EndOfWarrantyDate, Depth, RootId, ParentDate)
AS
(
-->>>>>>>>>>Root>>>>>>>>>>>>>>>>>
SELECT Id, Product, ParentProductId, Price, EndOfWarrantyDate, 0 as 'Depth', Id as 'RootId'
,EndOfWarrantyDate as 'ParentDate' -- new field
FROM @Products
WHERE ParentProductId IS NULL
-->>>>>>>>>>Root>>>>>>>>>>>>>>>>>
UNION ALL
-->>>>>>>>>>Children>>>>>>>>>>>>>>>>>
SELECT e.Id, e.Product, e.ParentProductId, e.Price, e.EndOfWarrantyDate, r.Depth + 1, r.RootId
,r.ParentDate -- new field
FROM @Products e
INNER JOIN cteProducts r
ON e.ParentProductId = r.Id
-->>>>>>>>>>Children>>>>>>>>>>>>>>>>>
)
SELECT ParentDate,
Id, Product, ParentProductId, Price, EndOfWarrantyDate, Depth, RootId
FROM cteProducts
order by ParentDate, Id; -- new field as first sort field
结果
ParentDate Id Product ParentProductId Price EndOfWarrantyDate Depth RootId
---------- ---------- -------------------- --------------- ----------- ----------------- ----------- ----------
2013-04-02 1 Vacuum NULL 130 2013-04-02 0 1
2013-04-02 1.1 Power Unit 1 200 2024-01-01 1 1
2013-04-02 1.1.1 Unit part 1.1 100 2024-01-01 2 1
2013-04-02 1.2 Filter 1 10 2022-07-15 1 1
2023-06-01 2 Laptop NULL 600 2023-06-01 0 2
2023-06-01 2.1 Hard Disk 2 200 2024-03-01 1 2
2023-12-01 3 Washing Machine NULL 1000 2023-12-01 0 3
我正在尝试实现以下要求:
我有一个产品及其备件的层次结构。这些备件可以在图表中包含其他部分,这些部分可能具有几层深度。
我的目标是编写一个 T-SQL 查询,允许我按 table 的任何列(在示例产品、价格或 EndOfWarrantyDate 中)进行排序,但保留层次结构。换句话说,我只想订购 parent 项,而不用担心应该只在 parent 之后发挥作用的 children .
在下面的示例中,如果您注意到,绿色行按“EndOfWarrantyDate”排序,但我仍想在 parent 旁边显示 children 和 sub-children (我不关心订购 children,只要尊重层次结构即可)。
注意:上面table中的Id只是为了更好地识别层次结构,在数据库中我有一个普通的标识列作为Id。
而且,如果可能的话,我想在单个 SQL 查询中执行此操作,而不必先收集 parent 项,订购它们,然后获取相关的 children 和子children.
目前我的CTE是这样的,但是我不知道如何实现排序。尝试使用分区,但不知道如何正确应用它来解决我的问题。
WITH
cteProducts (Id, Product, ParentProductId, Price, EndOfWarrantyDate, Depth, RootId)
AS
(
-->>>>>>>>>>Root>>>>>>>>>>>>>>>>>
SELECT Id, Product, ParentProductId, Price, EndOfWarrantyDate, 0 as Depth, Id as RootId
FROM Products
WHERE ParentProductId IS NULL
-->>>>>>>>>>Root>>>>>>>>>>>>>>>>>
UNION ALL
-->>>>>>>>>>Children>>>>>>>>>>>>>>>>>
SELECT e.Id, e.Product, e.ParentProductId, e.Price, e.EndOfWarrantyDate, r.Depth + 1, r.RootId
FROM Products e
INNER JOIN cteProducts r
ON e.ParentProductId = r.Id
-->>>>>>>>>>Children>>>>>>>>>>>>>>>>>
)
SELECT
Id, Product, ParentProductId, Price, EndOfWarrantyDate, Depth, RootId
FROM cteProducts
--ORDER BY RootId, EndOfWarrantyDate
非常感谢任何帮助,谢谢!
保留父 EndOfWarrantyDate
作为递归 CTE 的一部分。这样最后就可以排序了
示例数据
declare @Products table
(
Id nvarchar(10),
Product nvarchar(20),
ParentProductId nvarchar(10),
Price int,
EndOfWarrantyDate date
);
insert into @Products (Id, Product, ParentProductId, Price, EndOfWarrantyDate) values
('1', 'Vacuum', null, 130, '2013-04-02'),
('1.1', 'Power Unit', '1', 200, '2024-01-01'),
('1.1.1', 'Unit part', '1.1', 100, '2024-01-01'),
('1.2', 'Filter', '1', 10, '2022-07-15'),
('2', 'Laptop', null, 600, '2023-06-01'),
('2.1', 'Hard Disk', '2', 200, '2024-03-01'),
('3', 'Washing Machine', null, 1000, '2023-12-01');
解决方案
WITH
cteProducts (Id, Product, ParentProductId, Price, EndOfWarrantyDate, Depth, RootId, ParentDate)
AS
(
-->>>>>>>>>>Root>>>>>>>>>>>>>>>>>
SELECT Id, Product, ParentProductId, Price, EndOfWarrantyDate, 0 as 'Depth', Id as 'RootId'
,EndOfWarrantyDate as 'ParentDate' -- new field
FROM @Products
WHERE ParentProductId IS NULL
-->>>>>>>>>>Root>>>>>>>>>>>>>>>>>
UNION ALL
-->>>>>>>>>>Children>>>>>>>>>>>>>>>>>
SELECT e.Id, e.Product, e.ParentProductId, e.Price, e.EndOfWarrantyDate, r.Depth + 1, r.RootId
,r.ParentDate -- new field
FROM @Products e
INNER JOIN cteProducts r
ON e.ParentProductId = r.Id
-->>>>>>>>>>Children>>>>>>>>>>>>>>>>>
)
SELECT ParentDate,
Id, Product, ParentProductId, Price, EndOfWarrantyDate, Depth, RootId
FROM cteProducts
order by ParentDate, Id; -- new field as first sort field
结果
ParentDate Id Product ParentProductId Price EndOfWarrantyDate Depth RootId
---------- ---------- -------------------- --------------- ----------- ----------------- ----------- ----------
2013-04-02 1 Vacuum NULL 130 2013-04-02 0 1
2013-04-02 1.1 Power Unit 1 200 2024-01-01 1 1
2013-04-02 1.1.1 Unit part 1.1 100 2024-01-01 2 1
2013-04-02 1.2 Filter 1 10 2022-07-15 1 1
2023-06-01 2 Laptop NULL 600 2023-06-01 0 2
2023-06-01 2.1 Hard Disk 2 200 2024-03-01 1 2
2023-12-01 3 Washing Machine NULL 1000 2023-12-01 0 3