Wal*_*mar 3 t-sql sql-server hierarchy bigdata sql-server-2012
我有一个非常大的表,其层次结构无法修改。表中的节点有Id、ParentId、 aLevel和一些数据。这Level意味着具有 level 的节点N不仅可以是 level 的子节点,N-1还可以是 level 等的子节点。好消息是级别的数量是有限的 - 只有 8 个。级别 1 位于层次结构的顶部,级别 8 位于层次结构的末尾。N-2N-3
现在我需要根据关卡的位置压平该桌子。结果应该是这样的:
Lvl1 Lvl2 Lvl3 ... Lvl8
xxx xxx null xxx
xxx null xxx xxx
xxx null null xxx
xxx xxx xxx xxx
Run Code Online (Sandbox Code Playgroud)
第一步
由于关卡数量有限,第一个想法就是把LEFT JOIN所有的桌子都上几遍ParentId = Id。但这使得级别改变了位置,因为级别 6 可以被跳过,级别 5 取代了它的位置。
第二步所以我习惯CASE WHEN根据行的级别选择值。
-- LEVEL 4
CASE
WHEN lvl6.[Level] = 4 THEN lvl6.Data -- in case levels 6 and 5 were skipped, we can find 4th level data here
WHEN lvl5.[Level] = 4 THEN lvl5.Data
WHEN lvl4.[Level] = 4 THEN lvl4.Data
ELSE NULL
END AS l4Data,
Run Code Online (Sandbox Code Playgroud)
它解决了我的问题,但速度非常慢。
第三步关卡的组合也是有限的(1-2-3-4-5-6-7-8、1-3-5-6-7-8等),所以我决定使用 moreLEFT JOIN来将所有关卡组合粘合在一起:
WITH
l7 AS (SELECT * FROM myTable WHERE [Level] = 7),
l6 AS (SELECT * FROM myTable WHERE [Level] = 6),
...
FROM l7
...
LEFT JOIN l6 AS l6_7 ON l7.ParentId = l6_7.Id -- 7-6-5-4-1
LEFT JOIN l5 AS l5_7 ON l6_7.ParentId = l5_7.Id
LEFT JOIN l4 AS l4_7 ON l5_7.ParentId = l4_7.Id
LEFT JOIN l1 AS l1_7 ON l4_7.ParentId = l1_7.Id
Run Code Online (Sandbox Code Playgroud)
然后我使用以下方法选择数据COALESCE:
COALESCE(l3.Data, l3_1.Data, l3_2.Data, l3_3.Data) AS l3Data,
Run Code Online (Sandbox Code Playgroud)
它使我的查询非常复杂且难以扩展,但就目前而言,这是我取得的最快结果。
有没有更快、更小的方法可以让桌子变平?任何帮助将不胜感激。
提前致谢!
这是如何使用递归 CTE 的示例:
老实说:我没想到在处理大量数据时速度会非常快......
有HIERARCHYID数据类型,但你说,你不允许改变表的结构......
DECLARE @t TABLE(Name VARCHAR(100),id INT,parentId INT);
INSERT INTO @t VALUES
('Element 1',1,0)
,('Element 1.1',2,1)
,('Element 1.2',3,1)
,('Element 1.3',4,1)
,('Element 1.1.1',5,2)
,('Element 1.1.2',6,2)
,('Element 1.2.1',7,3)
,('Element 1.2.1.1',8,7)
,('Element 1.2.1.2',9,7);
WITH CTE AS
(
SELECT *
,CAST(parentId AS VARCHAR(MAX)) + ',' + CAST(CAST(id AS VARCHAR(MAX)) AS VARCHAR(MAX)) AS IdListTopDown
,CAST(Name AS varchar(MAX)) AS NameList
FROM @t
WHERE parentId = 0
UNION ALL
SELECT t.*
,CAST(c.IdListTopDown AS VARCHAR(MAX)) + ',' + CAST(CAST(t.id AS VARCHAR(MAX)) AS VARCHAR(MAX))
,CAST(c.NameList + ' | ' + t.Name AS varchar(MAX))
FROM @t AS t
JOIN CTE c ON c.id = t.parentId
)
SELECT CTE.*
FROM CTE
WHERE NOT EXISTS(SELECT * FROM @t WHERE parentId=CTE.id)
ORDER BY CTE.IdListTopDown
Run Code Online (Sandbox Code Playgroud)
结果
Element 1.1.1 5 2 0,1,2,5 Element 1 | Element 1.1 | Element 1.1.1
Element 1.1.2 6 2 0,1,2,6 Element 1 | Element 1.1 | Element 1.1.2
Element 1.2.1.1 8 7 0,1,3,7,8 Element 1 | Element 1.2 | Element 1.2.1 | Element 1.2.1.1
Element 1.2.1.2 9 7 0,1,3,7,9 Element 1 | Element 1.2 | Element 1.2.1 | Element 1.2.1.2
Element 1.3 4 1 0,1,4 Element 1 | Element 1.3
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13455 次 |
| 最近记录: |