【发布时间】:2016-06-03 17:01:09
【问题描述】:
我有一个非常大的表,其层次结构无法修改。表中的节点有Id、ParentId、Level 和一些数据。 Level 表示级别为N 的节点不仅可以是级别N-1 的子节点,还可以是级别N-2、N-3 等的子节点。好消息是级别的数量是有限的——有只有8个。级别 1 位于层次结构的顶部,级别 8 位于其末尾。
现在我需要根据关卡的位置将该表展平。结果应该是这样的:
Lvl1 Lvl2 Lvl3 ... Lvl8
xxx xxx null xxx
xxx null xxx xxx
xxx null null xxx
xxx xxx xxx xxx
第一步
由于级别数有限,第一个想法是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,
它解决了我的问题,但速度很慢。
第三步 关卡的组合也是有限的(1-2-3-4-5-6-7-8、1-3-5-6-7-8 等)所以我决定使用更多的LEFT JOINs 将所有关卡组合粘合在一起:
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
然后我使用COALESCE选择数据:
COALESCE(l3.Data, l3_1.Data, l3_2.Data, l3_3.Data) AS l3Data,
这使我的查询非常复杂且难以扩展,但就目前而言,这是我取得的最快结果。
有没有更快更小的方法来平整这张桌子?任何帮助将不胜感激。
提前致谢!
【问题讨论】:
-
典型用途是CTE,什么版本的SQL Server?
-
谢谢,如果下面的答案不清楚,请回复评论,我会发布一些东西
-
非常感谢您的帮助,因为我看不到 Shnugo 的答案如何处理跳过一个或多个级别的情况
-
一般来说,你可以有简洁的代码或快速的代码,但通常不能两者兼得
-
您可能需要在问题中澄清(请提供示例)是第 7 层上的给定节点 A 可以在第 2 层上具有直接父节点 B,并且没有定义中间层。如果您将其作为示例数据提供,每个人可能会更清楚(并确认此假设)
标签: sql-server tsql sql-server-2012 hierarchy bigdata