[英]What is the most efficient way to concatenate a string from all parent rows using T-SQL?
我有一個表,它有一個代表其父行的自引用外鍵。 為了以最簡單的形式說明問題,我們將使用下表:
CREATE TABLE Folder(
id int IDENTITY(1,1) NOT NULL, --PK
parent_id int NULL, --FK
folder_name varchar(255) NOT NULL)
我想創建一個標量值 function ,它將文件夾名稱及其所有父文件夾名稱的串聯字符串一直返回到根文件夾,該根文件夾將由 null parent_id 值指定。
我目前的解決方案是一種程序方法,我認為它並不理想。 這是我正在做的事情:
CREATE FUNCTION dbo.GetEntireLineage
(@folderId INT)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE @lineage VARCHAR(MAX)
DECLARE @parentFolderId INT
SELECT @lineage = folder_name, @parentFolderId = parent_id FROM Folder WHERE id = @folderId
WHILE NOT @parentFolderId IS NULL
BEGIN
SET @parentFolderId = (SELECT parent_id FROM Folder WHERE parent_id = @parentFolderId)
SET @lineage = (SELECT @lineage + '-' + (SELECT folder_name FROM Folder WHERE parent_id = @parentFolderId))
END
RETURN @lineage
END
有沒有更理想的方法來做到這一點? 我是一位經驗豐富的程序員,但 T-SQL 對我來說並不熟悉,我知道由於基於集合的數據的性質,這些問題通常需要不同的方法。 任何幫助找到解決方案或處理 T-SQL 的任何其他提示和技巧將不勝感激。
要確定性能,您需要進行測試。 我已經使用您的版本(稍作修改)和其他人建議的遞歸 CTE 版本進行了一些測試。
我在一個文件夾層次結構中使用了包含 2048 行的示例表,因此當將 2048 作為參數傳遞給 function 時,完成了 2048 個連接。
循環版本:
create function GetEntireLineage1 (@id int)
returns varchar(max)
as
begin
declare @ret varchar(max)
select @ret = folder_name,
@id = parent_id
from Folder
where id = @id
while @@rowcount > 0
begin
select @ret = @ret + '-' + folder_name,
@id = parent_id
from Folder
where id = @id
end
return @ret
end
統計數據:
SQL Server Execution Times:
CPU time = 125 ms, elapsed time = 122 ms.
遞歸 CTE 版本:
create function GetEntireLineage2(@id int)
returns varchar(max)
begin
declare @ret varchar(max);
with cte(id, name) as
(
select f.parent_id,
cast(f.folder_name as varchar(max))
from Folder as f
where f.id = @id
union all
select f.parent_id,
c.name + '-' + f.folder_name
from Folder as f
inner join cte as c
on f.id = c.id
)
select @ret = name
from cte
where id is null
option (maxrecursion 0)
return @ret
end
統計數據:
SQL Server Execution Times:
CPU time = 187 ms, elapsed time = 183 ms.
所以在這兩者之間,循環版本更有效,至少在我的測試數據上是這樣。 您需要測試您的實際數據才能確定。
編輯
for xml path('')
技巧的遞歸 CTE。
create function [dbo].[GetEntireLineage4](@id int)
returns varchar(max)
begin
declare @ret varchar(max) = '';
with cte(id, lvl, name) as
(
select f.parent_id,
1,
f.folder_name
from Folder as f
where f.id = @id
union all
select f.parent_id,
lvl + 1,
f.folder_name
from Folder as f
inner join cte as c
on f.id = c.id
)
select @ret = (select '-'+name
from cte
order by lvl
for xml path(''), type).value('.', 'varchar(max)')
option (maxrecursion 0)
return stuff(@ret, 1, 1, '')
end
統計數據:
SQL Server Execution Times:
CPU time = 31 ms, elapsed time = 37 ms.
除非您有非常深的層次結構或可以利用索引的非常大的數據集,否則 hierarchyid 通常是多余的。 在不更改架構的情況下,這是您可以獲得的最快速度。
with recursiveCTE (parent_id,concatenated_name) as (
select parent_id,folder_name
from folder
union all
select f.parent_id,r.concatenated_name +f.folder_name
from folder f
inner join recursiveCTE r on r.parent_id = f.id
)
select folder_name from recursiveCTE
這對你有用:
with cte (Parent_id, Path) as
(
select Parent_Id,Folder_Name
from folder
union all
select f.Parent_Id,r.Path + '\' + f.Folder_Name
from Folder as f
inner join cte as c on c.Parent_Id = f.Id
)
select Folder_Name from cte
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.