我試圖找出一種方法來處理這種層次結構,但我不確定如何去做。為了簡單起見,我制作了這個示例資料:
CREATE TABLE #EXAMPLE (
ID INT
, PARENT_ID INT
, [PATH] VARCHAR(1000)
, [TYPE] VARCHAR(10)
);
INSERT INTO #EXAMPLE ([ID], PARENT_ID, [PATH], [TYPE]) VALUES
(63812, 0, '/Home', 'Folder')
,(55225, 63812, '/Home/User1', 'Folder')
,(92901, 63812, '/Home/User2', 'Folder')
,(40353, 63812, '/Home/User3', 'Folder')
,(96959, 55225, '/Home/User1/Item1', 'File')
,(97231, 55225, '/Home/User1/Item2', 'File')
,(53339, 92901, '/Home/User2/Item1', 'File')
,(58034, 92901, '/Home/User2/Music', 'Folder')
,(65023, 58034, '/Home/User2/Music/Item1', 'File')
,(72657, 58034, '/Home/User2/Music/Item2', 'File')
,(19406, 58034, '/Home/User2/Music/Item3', 'File')
,(56515, 58034, '/Home/User2/Music/Item4', 'File')
,(68394, 58034, '/Home/User2/Music/Item5', 'File')
,(42813, 92901, '/Home/User2/Movies', 'Folder')
,(32781, 42813, '/Home/User2/Movies/Item1', 'File')
,(96579, 40353, '/Home/User3/Scripts', 'Folder')
,(36300, 96579, '/Home/User3/Scripts/Item1', 'File')
,(59930, 96579, '/Home/User3/Scripts/SQL', 'Folder')
,(83700, 59930, '/Home/User3/Scripts/SQL/Item1', 'File')
,(66753, 59930, '/Home/User3/Scripts/SQL/Item2', 'File')
,(34377, 96579, '/Home/User3/Scripts/Other', 'Folder')
,(20666, 34377, '/Home/User3/Scripts/Other/Item1', 'File')
,(23786, 34377, '/Home/User3/Scripts/Other/Item2', 'File')
,(87107, 34377, '/Home/User3/Scripts/Other/Item3', 'File')
,(29557, 34377, '/Home/User3/Scripts/Other/Item4', 'File')
SELECT E.*
FROM #EXAMPLE AS E
DROP TABLE #EXAMPLE
這是一個檔案路徑層次結構,我想要做的是最終生成一個報告,例如,“/Home”下有 16 個檔案,然后您可以向下鉆取到下一個層次結構級別并查看“/Home/User1”有 2 個檔案,“/Home/User2”有 7 個檔案,依此類推。
我可能想多了……但要這樣做,我相信我必須展示不同檔案路徑之間共有的元素。起初,我嘗試過這樣的事情(在表創建陳述句之后):
;WITH E_CTE AS (
SELECT E.ID, E.PARENT_ID, E.[PATH], E.[TYPE], [LVL] = 0--, [COMMON_ROOT] = SUBSTRING(E.[PATH], 0, 0)
FROM #EXAMPLE AS E
WHERE E.ID = 63812
UNION ALL
SELECT EXM.ID, EXM.PARENT_ID, EXM.[PATH], EXM.[TYPE], CTE.LVL 1--, SUBSTRING(EXM.[PATH], 0, CTE.LVL)
FROM E_CTE AS CTE
INNER JOIN #EXAMPLE AS EXM
ON CTE.ID = EXM.PARENT_ID
)
SELECT E.PARENT_ID, [PARENT_PATH] = ISNULL(EXM.[PATH], ''), E.ID, E.[PATH], E.[TYPE], E.LVL
FROM E_CTE AS E
LEFT JOIN #EXAMPLE AS EXM
ON E.PARENT_ID = EXM.ID
ORDER BY E.LVL, E.[PATH]
DROP TABLE #EXAMPLE
這給了我一個資料集,我可以在其中看到給定記錄的直接父級,但我看不到每個父級元素的分解。PARENT_PATH 和 PATH 的層次結構使它看起來像有 9 個父組,當我希望它顯示頂部有一個組“/Home”,第二級有三個組“/Home/User1”時, “/Home/User2”和“/Home/User3”等等。我得到的是我需要一個像這樣的資料集:
CREATE TABLE #EXAMPLE (
ID INT
, PARENT_ID INT
, LEVEL_0 VARCHAR(1000)
, LEVEL_1 VARCHAR(1000)
, LEVEL_2 VARCHAR(1000)
, LEVEL_3 VARCHAR(1000)
, LEVEL_4 VARCHAR(1000)
, [PATH] VARCHAR(1000)
, [TYPE] VARCHAR(10)
);
INSERT INTO #EXAMPLE ([ID], PARENT_ID, LEVEL_0, LEVEL_1, LEVEL_2, LEVEL_3, LEVEL_4, [PATH], [TYPE]) VALUES
(63812, 0, '/Home', NULL, NULL, NULL, NULL, '/Home', 'Folder')
,(55225, 63812, '/Home', '/Home/User1', NULL, NULL, NULL, '/Home/User1', 'Folder')
,(92901, 63812, '/Home', '/Home/User2', NULL, NULL, NULL, '/Home/User2', 'Folder')
,(40353, 63812, '/Home', '/Home/User3', NULL, NULL, NULL, '/Home/User3', 'Folder')
,(96959, 55225, '/Home', '/Home/User1', '/Home/User1/Item1', NULL, NULL, '/Home/User1/Item1', 'File')
,(97231, 55225, '/Home', '/Home/User1', '/Home/User1/Item2', NULL, NULL, '/Home/User1/Item2', 'File')
,(53339, 92901, '/Home', '/Home/User2', '/Home/User2/Item1', NULL, NULL, '/Home/User2/Item1', 'File')
,(58034, 92901, '/Home', '/Home/User2', '/Home/User2/Music', NULL, NULL, '/Home/User2/Music', 'Folder')
,(65023, 58034, '/Home', '/Home/User2', '/Home/User2/Music', '/Home/User2/Music/Item1', NULL, '/Home/User2/Music/Item1', 'File')
,(72657, 58034, '/Home', '/Home/User2', '/Home/User2/Music', '/Home/User2/Music/Item2', NULL, '/Home/User2/Music/Item2', 'File')
,(19406, 58034, '/Home', '/Home/User2', '/Home/User2/Music', '/Home/User2/Music/Item3', NULL, '/Home/User2/Music/Item3', 'File')
,(56515, 58034, '/Home', '/Home/User2', '/Home/User2/Music', '/Home/User2/Music/Item4', NULL, '/Home/User2/Music/Item4', 'File')
,(68394, 58034, '/Home', '/Home/User2', '/Home/User2/Music', '/Home/User2/Music/Item5', NULL, '/Home/User2/Music/Item5', 'File')
,(42813, 92901, '/Home', '/Home/User2', '/Home/User2/Movies', NULL, NULL, '/Home/User2/Movies', 'Folder')
,(32781, 42813, '/Home', '/Home/User2', '/Home/User2/Movies', '/Home/User2/Movies/Item1', NULL, '/Home/User2/Movies/Item1', 'File')
,(96579, 40353, '/Home', '/Home/User3', '/Home/User3/Scripts', NULL, NULL, '/Home/User3/Scripts', 'Folder')
,(36300, 96579, '/Home', '/Home/User3', '/Home/User3/Scripts', '/Home/User3/Scripts/Item1', NULL, '/Home/User3/Scripts/Item1', 'File')
,(59930, 96579, '/Home', '/Home/User3', '/Home/User3/Scripts', '/Home/User3/Scripts/SQL', NULL, '/Home/User3/Scripts/SQL', 'Folder')
,(83700, 59930, '/Home', '/Home/User3', '/Home/User3/Scripts', '/Home/User3/Scripts/SQL', '/Home/User3/Scripts/SQL/Item1', '/Home/User3/Scripts/SQL/Item1', 'File')
,(66753, 59930, '/Home', '/Home/User3', '/Home/User3/Scripts', '/Home/User3/Scripts/SQL', '/Home/User3/Scripts/SQL/Item2', '/Home/User3/Scripts/SQL/Item2', 'File')
,(34377, 96579, '/Home', '/Home/User3', '/Home/User3/Scripts', '/Home/User3/Scripts/Other', NULL, '/Home/User3/Scripts/Other', 'Folder')
,(20666, 34377, '/Home', '/Home/User3', '/Home/User3/Scripts', '/Home/User3/Scripts/Other', '/Home/User3/Scripts/Other/Item1', '/Home/User3/Scripts/Other/Item1', 'File')
,(23786, 34377, '/Home', '/Home/User3', '/Home/User3/Scripts', '/Home/User3/Scripts/Other', '/Home/User3/Scripts/Other/Item2', '/Home/User3/Scripts/Other/Item2', 'File')
,(87107, 34377, '/Home', '/Home/User3', '/Home/User3/Scripts', '/Home/User3/Scripts/Other', '/Home/User3/Scripts/Other/Item3', '/Home/User3/Scripts/Other/Item3', 'File')
,(29557, 34377, '/Home', '/Home/User3', '/Home/User3/Scripts', '/Home/User3/Scripts/Other', '/Home/User3/Scripts/Other/Item4', '/Home/User3/Scripts/Other/Item4', 'File')
SELECT * FROM #EXAMPLE
DROP TABLE #EXAMPLE
This dataset shows me each row-level item (folder or file), the path, but then the entire "shared path" at each level of the hierarchy. My question is, how do I get from my first dataset to this dataset, using T-SQL? (That is, how do I get to that dynamically?) It would involve a dynamic number of columns depending on how many levels there are (in the production data there's more like seven or eight levels).
A secondary question is this: is there an alternative way to arrange/tabulate/organize this data such that in a reporting tool like SSRS or Tableau, I could drill down from the top level down to the bottom level in the manner I've described?
Thanks to anyone who takes the time to look at this question.
uj5u.com熱心網友回復:
通過一些調查,我弄清楚了我需要什么,這不是我所要求的(沒有詞匯來知道確切地要求開始什么)。在查看了 Wise Owl 的鏈接(https://www.youtube.com/watch?v=CHbqIsw5X30&list=PLNIs-AWhQzcmEFHyxCRwA_gb29WOz5SJU&index=28)后,我還參考了 Itzik Ben-Gan (2015) 第 778 頁的T-SQL Querying 786 并提出了這個嵌套集合解決方案:
DECLARE @root AS INT = 63812;
CREATE TABLE #EXAMPLE (
ID INT
, PARENT_ID INT
, [PATH] VARCHAR(1000)
, [TYPE] VARCHAR(10)
);
INSERT INTO #EXAMPLE ([ID], PARENT_ID, [PATH], [TYPE]) VALUES
(63812, 0, '/Home', 'Folder')
,(55225, 63812, '/Home/User1', 'Folder')
,(92901, 63812, '/Home/User2', 'Folder')
,(40353, 63812, '/Home/User3', 'Folder')
,(96959, 55225, '/Home/User1/Item1', 'File')
,(97231, 55225, '/Home/User1/Item2', 'File')
,(53339, 92901, '/Home/User2/Item1', 'File')
,(58034, 92901, '/Home/User2/Music', 'Folder')
,(65023, 58034, '/Home/User2/Music/Item1', 'File')
,(72657, 58034, '/Home/User2/Music/Item2', 'File')
,(19406, 58034, '/Home/User2/Music/Item3', 'File')
,(56515, 58034, '/Home/User2/Music/Item4', 'File')
,(68394, 58034, '/Home/User2/Music/Item5', 'File')
,(42813, 92901, '/Home/User2/Movies', 'Folder')
,(32781, 42813, '/Home/User2/Movies/Item1', 'File')
,(96579, 40353, '/Home/User3/Scripts', 'Folder')
,(36300, 96579, '/Home/User3/Scripts/Item1', 'File')
,(59930, 96579, '/Home/User3/Scripts/SQL', 'Folder')
,(83700, 59930, '/Home/User3/Scripts/SQL/Item1', 'File')
,(66753, 59930, '/Home/User3/Scripts/SQL/Item2', 'File')
,(34377, 96579, '/Home/User3/Scripts/Other', 'Folder')
,(20666, 34377, '/Home/User3/Scripts/Other/Item1', 'File')
,(23786, 34377, '/Home/User3/Scripts/Other/Item2', 'File')
,(87107, 34377, '/Home/User3/Scripts/Other/Item3', 'File')
,(29557, 34377, '/Home/User3/Scripts/Other/Item4', 'File');
WITH TwoNums AS (
SELECT n FROM (VALUES(1), (2)) AS D(n)
)
, SortPath AS (
SELECT EXM.ID, EXM.[PATH], EXM.[TYPE], TN.n, [LVL] = 0, [SORT_PATH] = CONVERT(VARBINARY(MAX), CONVERT(BINARY(4), TN.n))
FROM #EXAMPLE AS EXM
CROSS JOIN TwoNums AS TN
WHERE EXM.ID = @root
UNION ALL
SELECT E.ID, E.[PATH], E.[TYPE], TNS.n, SP.LVL 1, SP.SORT_PATH CONVERT(BINARY(4), (-1 ROW_NUMBER() OVER(PARTITION BY E.PARENT_ID
ORDER BY E.[PATH])) / 2 * 2 TNS.n)
FROM SortPath AS SP
INNER JOIN #EXAMPLE AS E
ON SP.n = 1
AND E.PARENT_ID = SP.ID
CROSS JOIN TwoNums AS TNS
)
, Sort AS (
SELECT SP.ID, SP.[PATH], SP.[TYPE], [SortVal] = ROW_NUMBER() OVER(ORDER BY SP.SORT_PATH)
FROM SortPath AS SP
)
, NestedSets AS (
SELECT SRT.ID, SRT.[PATH], SRT.[TYPE], [LFT] = MIN(SRT.SortVal), [RGT] = MAX(SRT.SortVal)
FROM Sort AS SRT
GROUP BY SRT.ID, SRT.[PATH], SRT.[TYPE]
)
SELECT NS.*, EXM.PARENT_ID
INTO #StructureNS
FROM NestedSets AS NS
INNER JOIN #EXAMPLE AS EXM
ON NS.ID = EXM.ID;
SELECT NS.PARENT_ID, NS.ID, NS.[PATH], NS.[TYPE]
, [CNT_FILES] =
(SELECT COUNT(DISTINCT CHLD.ID)
FROM #StructureNS AS PRNT
INNER JOIN #StructureNS AS CHLD
ON CHLD.LFT BETWEEN PRNT.LFT AND PRNT.RGT
WHERE CHLD.RGT - CHLD.LFT = 1
AND PRNT.[TYPE] = 'Folder'
AND CHLD.[TYPE] = 'File'
AND NS.ID = PRNT.ID
)
FROM #StructureNS AS NS
DROP TABLE #EXAMPLE, #StructureNS
我所追求的是如何在給定遞回層次結構的每個級別執行各種聚合(例如檔案計數)。T-SQL 代碼很好地做到了這一點,但似乎可以使用 SSRS 和“遞回”引數。無論哪種方式,SSRS 遞回高級設定都允許我以我正在尋找的方式顯示資料,即從根向下鉆取所有節點。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/405458.html
標籤:
