【问题标题】:Create a pivoted/flattened hierarchies table from a path enumeration column从路径枚举列创建一个透视/扁平层次结构表
【发布时间】:2022-11-16 23:46:21
【问题描述】:

我有一个带有路径枚举列(沿袭列)的层次结构表

我的表:

path desc lvl
D Chicago 1
DADB Los Angeles 2
DADB761 Miami 3
DADB761G93 Detroit 4
DADB761G93276 San Francisco 5
DADB761G93277 Seattle 5

期望的结果:

desc1 desc2 desc3 desc4 desc5 code1 code2 code3 code4 code5
Chicago Los Angeles Miami Detroit San Francisco D ADB 761 G93 276
Chicago Los Angeles Miami Detroit Seattle D ADB 761 G93 277

假设递归 CTE 是最佳路径,我如何生成所需的结果表?

重现表的 SQL 语句:

create table dbo.#mytable (
    [path] VARCHAR(13),
    [desc] VARCHAR(70),
    [lvl] SMALLINT
)

insert into #mytable([path],[desc],[lvl]) 
values('D','Chicago',1),('DADB','Los Angeles',2),('DADB761','Miami',3),('DADB761G93','Detroit',4),
('DADB761G93276','San Francisco',5),('DADB761G93277','Seattle',5)

【问题讨论】:

    标签: sql sql-server common-table-expression hierarchy recursive-query


    【解决方案1】:

    通常,您会使用递归 CTE 中多行的数据构建 [path] 列。在这种情况下,您正在“展平”多行表格。如果您有超过 5 个级别,这不会自动扩展。您必须为每个级别添加一列。话虽如此,您可以像这样做您要问的事情:

    SQL Fiddle

    MS SQL Server 2017 架构设置:

    CREATE TABLE mytable (
        [path] VARCHAR(13) null,
        [desc] VARCHAR(70) null,
        [lvl] SMALLINT null
    )
    
    INSERT INTO mytable ([path],[desc],[lvl]) 
    VALUES
      ('D','Chicago',1)
      ,('DADB','Los Angeles',2)
      ,('DADB761','Miami',3)
      ,('DADB761G93','Detroit',4)
      ,('DADB761G93276','San Francisco',5)
      ,('DADB761G93277','Seattle',5)
    

    查询 1:

    WITH destruct AS (
    
      SELECT DISTINCT 
        CAST([path] as nvarchar(512)) as code1
        , CAST('' as nvarchar(512)) as code2
        , CAST('' as nvarchar(512)) as code3
        , CAST('' as nvarchar(512)) as code4
        , CAST('' as nvarchar(512)) as code5
        , CAST([desc] as nvarchar(512)) as desc1
        , CAST('' as nvarchar(512)) as desc2
        , CAST('' as nvarchar(512)) as desc3
        , CAST('' as nvarchar(512)) as desc4
        , CAST('' as nvarchar(512)) as desc5
        , mt.[path]
        , mt.lvl
      FROM mytable as mt
      WHERE lvl = 1
    
      UNION ALL
    
      SELECT
        CAST(d.code1 as nvarchar(512)) as code1
        , CAST(CASE WHEN d.lvl + 1 = 2 THEN RIGHT(mt.[path], LEN(mt.[path])-LEN(d.[path])) ELSE d.code2 END as nvarchar(512)) as code2
        , CAST(CASE WHEN d.lvl + 1 = 3 THEN RIGHT(mt.[path], LEN(mt.[path])-LEN(d.[path])) ELSE d.code3 END as nvarchar(512)) as code3
        , CAST(CASE WHEN d.lvl + 1 = 4 THEN RIGHT(mt.[path], LEN(mt.[path])-LEN(d.[path])) ELSE d.code4 END as nvarchar(512)) as code4
        , CAST(CASE WHEN d.lvl + 1 = 5 THEN RIGHT(mt.[path], LEN(mt.[path])-LEN(d.[path])) ELSE d.code5 END as nvarchar(512)) as code5
        , CAST(d.desc1 as nvarchar(512)) as desc1
        , CAST(CASE WHEN d.lvl + 1 = 2 THEN mt.[desc] ELSE d.desc2 END as nvarchar(512)) as desc2
        , CAST(CASE WHEN d.lvl + 1 = 3 THEN mt.[desc] ELSE d.desc3 END as nvarchar(512)) as desc3
        , CAST(CASE WHEN d.lvl + 1 = 4 THEN mt.[desc] ELSE d.desc4 END as nvarchar(512)) as desc4
        , CAST(CASE WHEN d.lvl + 1 = 5 THEN mt.[desc] ELSE d.desc5 END as nvarchar(512)) as desc5
        , mt.[path]
        , mt.lvl
      FROM destruct as d
        INNER JOIN mytable as mt
          ON mt.lvl = d.lvl + 1
          AND mt.[path] like d.[path] + '%'
      AND d.lvl < 20  --Safety for debugging. Remove in Production.
    )
    SELECT *
    FROM destruct as d
    WHERE d.lvl = 5
    

    Results:

    | code1 | code2 | code3 | code4 | code5 |   desc1 |       desc2 | desc3 |   desc4 |         desc5 |          path | lvl |
    |-------|-------|-------|-------|-------|---------|-------------|-------|---------|---------------|---------------|-----|
    |     D |   ADB |   761 |   G93 |   276 | Chicago | Los Angeles | Miami | Detroit | San Francisco | DADB761G93276 |   5 |
    |     D |   ADB |   761 |   G93 |   277 | Chicago | Los Angeles | Miami | Detroit |       Seattle | DADB761G93277 |   5 |
    

    注意:所有CAST 表达式都是为了确保根查询和子查询具有相同的数据类型。如果没有它们,SQL Fiddle 会抛出有关类型不匹配的错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-25
      • 2018-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多