[英]SQL to ensure unique node names in adjacency list
所以我有一個鄰接列表,其中 forms 是一個模擬版本化文件結構的層次結構。 問題是傳入的文件名當前不是唯一的,它們必須是唯一的。 為了讓事情變得更有趣,這些文件可能有不同的版本,應該保留第一個版本的名稱(注意所有版本都具有相同的 NodeID)。
父母ID | 節點ID | 版本號 | 文件名 |
---|---|---|---|
-1 | 1 | 1 | 第一文件夾 |
1 | 2 | 1 | 第二文件夾 |
1 | 3 | 1 | 第三文件夾 |
1 | 4 | 1 | 第一文件 |
1 | 4 | 2 | 第一文件 |
1 | 5 | 1 | 第一文件 |
1 | 5 | 2 | 第一文件 |
2 | 6 | 1 | 第一文件 |
2 | 6 | 2 | 第一文件 |
2 | 7 | 1 | 第二文件 |
3 | 8 | 1 | 第二文件 |
3 | 9 | 1 | 第三文件 |
3 | 9 | 2 | 第三文件 |
3 | 10 | 1 | 第三文件 |
3 | 11 | 1 | 第三文件 |
父母ID | 節點ID | 版本號 | 文件名 |
---|---|---|---|
-1 | 1 | 1 | 第一文件夾 |
1 | 2 | 1 | 第二文件夾 |
1 | 3 | 1 | 第三文件夾 |
1 | 4 | 1 | 第一文件 |
1 | 4 | 2 | 第一文件 |
1 | 5 | 1 | 第一個文檔_1 |
1 | 5 | 2 | 第一個文檔_1 |
2 | 6 | 1 | 第一文件 |
2 | 6 | 2 | 第一文件 |
2 | 7 | 1 | 第二文件 |
3 | 8 | 1 | 第二文件 |
3 | 9 | 1 | 第三文件 |
3 | 9 | 2 | 第三文件 |
3 | 10 | 1 | 第三文檔_1 |
3 | 11 | 1 | 第三文檔_2 |
*我還應該注意,文件夾名稱已經保證是唯一的(它們已經存在,它是傳入的文檔)並且它們只有 1 個版本。
CREATE TABLE #tmp_tree
(
ParentID INT,
NodeID INT,
VersionNum INT,
FileName VARCHAR(50),
);
INSERT INTO #tmp_tree (ParentID, NodeID, VersionNum, FileName)
VALUES (-1, 1, 1, 'FirstFolder' ),
(1, 2, 1, 'SecondFolder' ),
(1, 3, 1, 'ThirdFolder' ),
(1, 4, 1, 'FirstDocument' ),
(1, 4, 2, 'FirstDocument' ),
(1, 5, 1, 'FirstDocument' ),
(1, 5, 2, 'FirstDocument' ),
(2, 6, 1, 'FirstDocument' ),
(2, 6, 2, 'FirstDocument' ),
(2, 7, 1, 'SecondDocument' ),
(3, 8, 1, 'SecondDocument' ),
(3, 9, 1, 'ThirdDocument' ),
(3, 9, 2, 'ThirdDocument' ),
(3, 10, 1, 'ThirdDocument' )
(3, 11, 1, 'ThirdDocument' )
我真的不知道如何通過存儲過程來解決這個問題。 鄰接列表向我尖叫 CTE,但這讓我沒有真正的快。 Group By 丟失了 NodeID,因此雖然我可以找到需要重命名的文檔的名稱 - 我不知道如何將其用於 select 第二次出現的名稱(按 NodeID 排序)。
-- I don't see how this helps... but this finds the names that need to change.
select ParentID, FileName,VersionNum, count(*) from #tmp_tree
GROUP BY ParentID, FileName, VersionNum
HAVING VersionNum = 1 and count(*) > 1
order by FileName
我知道如何解決這個程序,但不是聲明式的。
我不知道這是離解決方案更近還是更遠:
select f2.*, Row_Number() over (order by f2.FileName) from
(select top 10 f.*, count(FileName) over (PARTITION by ParentID, FileName) as n from (select * from #tmp_tree where versionNum = 1) as f
order by f.ParentID, f.FileName) as f2
Where n > 1
我會假設目標結果中的最后一行 (3, 11) 是一個錯誤。
您可以在子查詢中找到帶有 window function 的重復名稱,然后在更新期間加入它。 簡而言之,您可以這樣做:
update #tmp_tree
set #tmp_tree.filename = concat(#tmp_tree.filename, '_', x.rn)
from #tmp_tree
join (
select *,
row_number() over(partition by parentid, filename order by nodeid) as rn
from #tmp_tree
where versionnum = 1
) x on x.rn > 1 and x.nodeid = #tmp_tree.nodeid;
結果:
ParentID NodeID VersionNum FileName
--------- ------- ----------- ---------------
-1 1 1 FirstFolder
1 2 1 SecondFolder
1 3 1 ThirdFolder
1 4 1 FirstDocument
1 4 2 FirstDocument
1 5 1 FirstDocument_2
1 5 2 FirstDocument_2
2 6 1 FirstDocument
2 6 2 FirstDocument
2 7 1 SecondDocument
3 8 1 SecondDocument
3 9 1 ThirdDocument
3 9 2 ThirdDocument
3 10 1 ThirdDocument_2
請參閱db<>fiddle的運行示例。
您不需要自連接表,您可以直接更新派生表,使用DENSE_RANK
計算行數后
update x
set filename = concat(x.filename, '_', x.rn)
from (
select *,
dense_rank() over(partition by parentid, filename order by nodeid) as rn
from #tmp_tree
) x
where x.rn > 1;
DENSE_RANK
將根據 ordering 子句為並列結果返回相同的數字。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.