如何从SQL Server数据库中的平面表中提取层次结构

问题描述 投票:0回答:3

我想从sql server数据库中的表中提取层次结构。表格看起来与此类似,等级达到 10 级:

lvl1 lvl2 lvl3

我想从sql server数据库中的表中提取层次结构。表格看起来与此类似,等级达到 10 级:

lvl1 lvl2 lvl3
甲骨文 营销部 互联网
甲骨文 律师单位 知识分子
甲骨文 财务部
甲骨文 律师单位 司法部门
甲骨文 IT 部门 数据库
甲骨文 营销部 电视
甲骨文 IT 部门 企业资源计划

这就是我想要得到的:

  • 甲骨文
    • 营销单位
      • 互联网
      • 电视
    • 律师单位
      • 知识分子
      • 司法部门
    • 财务部
    • IT单位
      • 数据库
      • 企业资源计划

我阅读了有关 SQL 分层查询的内容,但我不知道如何使用我的表结构来做到这一点...

我会很感激你的帮助,有什么想法吗?

我用过unpivot,结果

Oracle
-list of all level 2
-list of all level 3
甲骨文 营销部 互联网
甲骨文 律师单位 知识分子
甲骨文 财务部
甲骨文 律师单位 司法部门
甲骨文 IT 部门 数据库
甲骨文 营销部 电视
甲骨文 IT 部门 企业资源计划
sql-server tsql hierarchical-clustering
3个回答
1
投票

我不确定您打算将这些结果用于什么,大多数情况下需要定义某种关系,但是要复制您声明的所需输出,您可以使用:

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
行。


0
投票

你的结构有点笨拙,但这很容易扩展到 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

结果


0
投票

我认为可能有更简单的方法,除非我错过了重点。为什么不简单地分组和排序呢?你可以用中间的“go”来做一系列这样的事情,或者只是一张大桌子:

选择 lvl1, lvl2, lvl3, ... lvn 从表 按 lvl2、lvl3、....lvn 订购;

或者做每个级别的汇总查询

选择lvl2,lvl3 从表 按 lvl3 排序 去 选择lvl3,lvl4 从表 按 lvl4 排序 去 ... 选择 lv(n-1),n 从表 按 n

排序

但我可能忽略了重点,因为这很简单。我只是想把它包括在内,因为有人曾经给过我一个简单的答案,而且是正确的。

© www.soinside.com 2019 - 2024. All rights reserved.