示例表:
CREATE TABLE Fruit (
ID int identity(1,1) NOT NULL,
ParentID int NULL,
Name varchar(255)
);
我想按字母顺序(多个级别深度)对同一个表中的父记录和子记录进行排序:
Apples
--Green
----Just Sour
----Really Sour
--Red
----Big
----Small
Bananas
--etc.
我试过这个:
;WITH CTE(ID, ParentID, Name, Sort) AS
(
SELECT
ID
,ParentID
,Name
,cast('\' + Name as nvarchar(255)) AS Sort
FROM Fruit
WHERE ParentID IS NULL
UNION ALL
SELECT
a.ID
,a.ParentID
,a.Name
,cast(b.Sort + '\' + a.Name as nvarchar(255)) AS Sort
FROM Fruit a
INNER JOIN CTE b ON a.ParentID = b.ID
)
SELECT * FROM CTE Order by Sort
这会产生类似的结果:
\Apples
\Apples\Green
\Apples\Green\Just Sour
\etc.
就在我认为事情好的时候,它是不可靠的。例如,如果一个项目有多个单词。像:
\Apples
\Apples A <-- culprit
\Apples\Green
如果我可以扩展我的问题,我想在结果中显示实际的连字符或其他内容:
Parent
- Child
--Grandchild
我快速做到这一点的方法是在表中添加一个前缀列,其值为-
,用于所有记录。然后我可以这样做:
;WITH CTE(ID, ParentID, Name, Sort, Prefix) AS
(
SELECT
ID
,ParentID
,Name
,cast('\' + Name as nvarchar(255)) AS Sort
,Prefix
FROM Fruit
WHERE ParentID IS NULL
UNION ALL
SELECT
a.ID
,a.ParentID
,a.Name
,cast(b.Sort + '\' + a.Name as nvarchar(255)) AS Sort
,cast(b.Prefix + a.Prefix as nvarchar(10)) AS Prefix
FROM Fruit a
INNER JOIN CTE b ON a.ParentID = b.ID
)
SELECT * FROM CTE Order by Sort
但这似乎不正确或不是最佳的。
这些分层查询仍让我头疼,所以也许我只是没有看到明显的问题。
答案 0 :(得分:1)
我猜你想要这个结果
\Apples
\Apples\Green
\Apples A
也许尝试这样的事情:
SELECT *
FROM CTE
ORDER BY replace(Sort, ' ', '~')
'~'
是ascii 126,您还可以使用excel排序进行检查。
答案 1 :(得分:1)
在这种情况下,我倾向于使用按名称排序的row_number()
示例强>
Declare @YourTable table (id int,ParentId int,Name varchar(50))
Insert into @YourTable values
( 1, NULL,'Apples')
,( 2, 1 ,'Green')
,( 3, 2 ,'Just Sour')
,( 4, 2 ,'Really Sour')
,( 5, 1 ,'Red')
,( 6, 5 ,'Big')
,( 7, 5 ,'Small')
,( 8, NULL,'Bananas')
Declare @Top int = null --<< Sets top of Hier Try 5
Declare @Nest varchar(25) = '|-----' --<< Optional: Added for readability
;with cteP as (
Select Seq = cast(1000+Row_Number() over (Order by Name) as varchar(500))
,ID
,ParentId
,Lvl=1
,Name
From @YourTable
Where IsNull(@Top,-1) = case when @Top is null then isnull(ParentId ,-1) else ID end
Union All
Select Seq = cast(concat(p.Seq,'.',1000+Row_Number() over (Order by r.Name)) as varchar(500))
,r.ID
,r.ParentId
,p.Lvl+1
,r.Name
From @YourTable r
Join cteP p on r.ParentId = p.ID)
Select A.ID
,A.ParentId
,A.Lvl
,Name = Replicate(@Nest,A.Lvl-1) + A.Name
,Seq --<< Can be removed
From cteP A
Order By Seq
<强>返回强>
ID ParentId Lvl Name Seq
1 NULL 1 Apples 1001
2 1 2 |-----Green 1001.1001
3 2 3 |-----|-----Just Sour 1001.1001.1001
4 2 3 |-----|-----Really Sour 1001.1001.1002
5 1 2 |-----Red 1001.1002
6 5 3 |-----|-----Big 1001.1002.1001
7 5 3 |-----|-----Small 1001.1002.1002
8 NULL 1 Bananas 1002