我想从sql server数据库中的表中提取层次结构。表格看起来与此类似,等级达到 10 级:
lvl1 | lvl2 | lvl3 |
---|
我想从sql server数据库中的表中提取层次结构。表格看起来与此类似,等级达到 10 级:
lvl1 | lvl2 | lvl3 |
---|---|---|
甲骨文 | 营销部 | 互联网 |
甲骨文 | 律师单位 | 知识分子 |
甲骨文 | 财务部 | 空 |
甲骨文 | 律师单位 | 司法部门 |
甲骨文 | IT 部门 | 数据库 |
甲骨文 | 营销部 | 电视 |
甲骨文 | IT 部门 | 企业资源计划 |
这就是我想要得到的:
我阅读了有关 SQL 分层查询的内容,但我不知道如何使用我的表结构来做到这一点...
我会很感激你的帮助,有什么想法吗?
我用过unpivot,结果
Oracle
-list of all level 2
-list of all level 3
甲骨文 | 营销部 | 互联网 |
甲骨文 | 律师单位 | 知识分子 |
甲骨文 | 财务部 | 空 |
甲骨文 | 律师单位 | 司法部门 |
甲骨文 | IT 部门 | 数据库 |
甲骨文 | 营销部 | 电视 |
甲骨文 | IT 部门 | 企业资源计划 |
我不确定您打算将这些结果用于什么,大多数情况下需要定义某种关系,但是要复制您声明的所需输出,您可以使用:
DECLARE @TABLE TABLE (lvl1 NVARCHAR(50), lvl2 NVARCHAR(50), lvl3 NVARCHAR(50));
INSERT INTO @TABLE (lvl1, lvl2, lvl3) VALUES
('Oracle', 'Marketing unit', 'Internet '), ('Oracle', 'Lawyers unit ', 'Intellectual '),
('Oracle', 'Finance unit ', NULL), ('Oracle', 'Lawyers unit ', 'Judicial department'),
('Oracle', 'IT unit ', 'Database '), ('Oracle', 'Marketing unit', 'Television '),
('Oracle', 'IT unit ', 'ERP ');
;WITH base AS (
SELECT DISTINCT lvl1, '' AS lvl2, '' AS lvl3
FROM @TABLE
UNION ALL
SELECT DISTINCT lvl1, lvl2, ''
FROM @TABLE
UNION ALL
SELECT DISTINCT lvl1, lvl2, lvl3
FROM @TABLE
WHERE lvl3 IS NOT NULL
)
SELECT CONCAT(CASE WHEN LAG(lvl1,1) OVER (ORDER BY lvl1, lvl2, lvl3) IS NULL THEN lvl1 WHEN LAG(lvl1,1) OVER (ORDER BY lvl1, lvl2, lvl3) = lvl1 THEN CHAR(9)+' - ' ELSE lvl1 END,
CASE WHEN LAG(lvl2,1) OVER (ORDER BY lvl1, lvl2, lvl3) IS NULL THEN lvl2 WHEN LAG(lvl2,1) OVER (ORDER BY lvl1, lvl2, lvl3) = lvl2 THEN CHAR(9)+' - ' ELSE lvl2 END,
lvl3)
FROM base
ORDER BY lvl1, lvl2, lvl3
lvl1 | lvl2 | lvl3 |
---|---|---|
甲骨文 | ||
-财务部 | ||
- IT 部门 | ||
- | - 数据库 | |
- | -企业资源规划 | |
- 律师单位 | ||
- | -知识分子 | |
- | -司法部门 | |
- 营销部门 | ||
- | - 互联网 | |
- | - 电视 |
我们在这里所做的就是为组制作单独的行,然后将它们粘在一起,同时使用LAG()
比较this行与
last行。
你的结构有点笨拙,但这很容易扩展到 10 级
您可能会注意到兄弟姐妹是按字母顺序排列的,如果您想要特定的顺序,则需要另一列具有正确的顺序/顺序。
示例或 dbFiddle
DECLARE @YourTable TABLE (lvl1 VARCHAR(50), lvl2 VARCHAR(50), lvl3 VARCHAR(50));
INSERT INTO @YourTable (lvl1, lvl2, lvl3) VALUES
('Oracle', 'Marketing unit', 'Internet'), ('Oracle', 'Lawyers unit ', 'Intellectual '),
('Oracle', 'Finance unit', NULL), ('Oracle', 'Lawyers unit ', 'Judicial department'),
('Oracle', 'IT unit', 'Database'), ('Oracle', 'Marketing unit', 'Television '),
('Oracle', 'IT unit', 'ERP');
;with cte0 as ( Select Distinct Pt=Lvl1+null,ID=Lvl1 From @YourTable Where Lvl1 is not null )
,cte1 as ( Select Distinct Pt=Lvl1 ,ID=Lvl2 From @YourTable Where Lvl2 is not null )
,cte2 as ( Select Distinct Pt=Lvl2 ,ID=Lvl3 From @YourTable Where Lvl3 is not null )
,cteC as (
Select * from cte0
Union All
Select * from cte1
Union All
Select * from cte2
),
cteOH as (
Select *,Lvl=1,SPath=convert(varchar(500),ID) From cteC Where Pt is null
Union All
Select h.Pt,h.ID,Lvl=cteOH.Lvl+1,sPath=convert(varchar(500),cteOH.sPath+'/'+h.ID) FROM cteC H join cteOH ON h.Pt = cteOH.ID
)
Select Lvl
,ID
,Pt
,Nested = replicate('|---',Lvl-1)+ID
From cteOH
Order By sPath
结果
我认为可能有更简单的方法,除非我错过了重点。为什么不简单地分组和排序呢?你可以用中间的“go”来做一系列这样的事情,或者只是一张大桌子:
选择 lvl1, lvl2, lvl3, ... lvn 从表 按 lvl2、lvl3、....lvn 订购;
或者做每个级别的汇总查询
选择lvl2,lvl3 从表 按 lvl3 排序 去 选择lvl3,lvl4 从表 按 lvl4 排序 去 ... 选择 lv(n-1),n 从表 按 n
排序但我可能忽略了重点,因为这很简单。我只是想把它包括在内,因为有人曾经给过我一个简单的答案,而且是正确的。