【问题标题】:Recursive CTE with order by具有 order by 的递归 CTE
【发布时间】:2012-08-16 00:53:29
【问题描述】:

我正在处理分层数据并使用递归 CTE 来列出这样的项目:

Eletronics
    Televisions
        Tube
        LCD
        Plasma
    Portable Electronic
        MP3 Players
            Flash
        CD Player
        Two Way Radios

我的问题是:
如何按照标题排序并尊重层次结构?

像这样:

Eletronics
    Portable Electronic
        CD Player
        MP3 Players
            Flash
        Two Way Radios
    Televisions
        LCD
        Plasma
        Tube

Tks

【问题讨论】:

  • 不看代码怎么办
  • 数据库软件及其版本的选择对可能的解决方案有相当大的影响。跑什么?
  • A real recursion with CTE? 的可能重复项

标签: tsql recursion sql-order-by common-table-expression


【解决方案1】:

这是正确的 CTE(仅适用于 asc)

;WITH CTE AS
(
SELECT  id, id_parent, name_product
        ,HierarchicalPath = CAST('\'+CAST(name_product AS VARCHAR(MAX)) AS VARCHAR(MAX)) 
FROM @tab where id_parent is null -- Starts with the first level

UNION ALL

SELECT  t.id, t.id_parent, t.name_product
        ,HierarchicalPath = CAST(c.HierarchicalPath + '\'+CAST(t.name_product AS VARCHAR(MAX)) AS VARCHAR(MAX))
FROM @tab t INNER JOIN CTE C
ON t.id_parent = C.id
)

select * from cte order by HierarchicalPath

【讨论】:

    【解决方案2】:

    这是我几乎完成了我想要的代码。 现在的问题是按desc排序

    declare @tab table(
        id int identity(1,1)
        ,id_parent int
        ,name_product varchar(100)
    )
    
    insert into @tab
    select null, 'Eletronics'
    union all
    select 1, 'Televisions'
    union all
    select 2, 'Tube'
    union all
    select 2, 'LCD'
    union all
    select 2, 'Plasma'
    union all
    select 1, 'Portable Electronic'
    union all
    select 6, 'MP3 Players'
    union all
    select 7, 'Flash'
    union all
    select 6, 'CD Player'
    union all
    select 6, 'Two Way Radios'
    
    ;WITH CTE (id,id_parent,name_product,LEVEL,SORTKEY)AS
    (
        SELECT id, id_parent, name_product, 1, CAST(name_product AS VARBINARY(MAX))
        FROM @tab where id_parent is null -- Starts with the first level
    
        UNION ALL
    
        SELECT t.id, t.id_parent, t.name_product, C.LEVEL + 1, CAST(C.SORTKEY + CAST(t.name_product AS VARBINARY(MAX)) AS VARBINARY(MAX))
        FROM @tab t INNER JOIN CTE C
        ON t.id_parent = C.id
    )
    
    select * from cte order by SORTKEY
    

    Tks

    【讨论】:

    • 如果我只能订购特定级别,那没关系。
    • 在最终语句中更改 order by 子句以包含 LEVEL 列,例如'按级别排序,排序键'
    • 这样的话,孩子就不会跟着父母了
    【解决方案3】:

    基于@onaiggac 的变体(你可以使用他的数据:-))

    ;WITH CTE (id, id_parent, name_product, LEVEL, SORTKEY) AS
    (
        SELECT id, id_parent, name_product, 1, 
            CAST(ROW_NUMBER() OVER (ORDER BY name_product) AS VARBINARY(MAX))
        FROM @tab where id_parent is null -- Starts with the first level
    
        UNION ALL
    
        SELECT t.id, t.id_parent, t.name_product, C.LEVEL + 1, 
            C.SORTKEY + CAST(ROW_NUMBER() OVER (ORDER BY t.name_product) AS VARBINARY(MAX))
        FROM @tab t 
        INNER JOIN CTE C ON t.id_parent = C.id
    )
    
    SELECT id, id_parent, REPLICATE('   ', LEVEL - 1) + name_product, LEVEL, SORTKEY FROM CTE ORDER BY SORTKEY
    

    这里的诀窍是使用

    ROW_NUMBER() OVER (ORDER BY name_product)
    

    进行“内部”排序。与@onaiggac 一样,然后将其组合成二进制varbinary(max)

    CAST(ROW_NUMBER() OVER (ORDER BY name_product) AS VARBINARY(MAX))
    

    然后递归相加...

    C.SORTKEY + CAST(ROW_NUMBER() OVER (ORDER BY t.name_product) AS VARBINARY(MAX))
    

    请注意,ROW_NUMBER() 将返回 bigint...您可以先将其转换为 int,然后再将其转换为 VARBINARY(MAX),例如

    CAST(CAST(ROW_NUMBER() OVER (ORDER BY name_product) AS INT) AS VARBINARY(MAX))
    

    如果你真的想要...我认为没有必要,除非你的树真的很深。

    【讨论】:

      猜你喜欢
      • 2012-02-16
      • 2012-12-07
      • 2017-06-28
      • 1970-01-01
      • 2022-01-01
      • 2011-07-21
      • 2019-02-17
      • 2014-04-01
      • 2011-07-03
      相关资源
      最近更新 更多