【问题标题】:SQL Server 2008 R2 - Recursive SQL - Is this possible?SQL Server 2008 R2 - 递归 SQL - 这可能吗?
【发布时间】:2017-01-20 01:37:00
【问题描述】:

我有下表:

| Article-Material1 | Article-Material2 |
|-------------------|-------------------|
| article001        | article002        |
| article001        | article003        |
| article001        | material001       |
| material001       |                   |
| article002        | article004        |
| article002        | material002       |
| material002       |                   |
| article003        | material003       |
| material003       |                   |
| article004        | material004       |
| material004       |                   |
| article005        | article010        |
| article005        | article011        |
| article005        | material001       |
| article010        | material005       |
| material005       |                   |
| article011        | article012        |
| article011        | material004       |
| article011        | material006       |
| material006       |                   |
| article012        | material002       |
| article012        | material007       |
| material007       |                   |

我想实现这样的输出:

article001
    |- article002
        |- article004
            |- material004
        |- material002
    |- article003
        |- material003
    |- material001
article005
    |- article010
        |- material005
    |- article011
        |- article012
            |- material002
            |- material007
        |- material004
        |- material006
    |- material001

我不知道这是否可以通过 SQL 实现。如果不可能,我还能尝试什么方向正确?

【问题讨论】:

  • 该输出在表格形式中的外观如何?还是以这种方式格式化的一个字符串?
  • 有可能,但您的输出不是表格。您是否打算让 SQL 打印一些东西?返回 XML?包括空列?重复列值? SQL Server 没有嵌套表的概念(大多数数据库系统没有,有极少数例外)。
  • @Stephen 这是我的许多问题之一。我不知道怎么把它放在桌子上。我需要一行包含每篇主要文章的所有子元素(仅存在于第一个层次结构上的文章)。我需要知道子元素在哪个层次上存在。最终目标是将数据导出到 Excel 文件。在 excel 文件中,我需要上面的输出。
  • @JeroenMostert 我希望有类似嵌套数据的东西。这肯定会使任务变得更容易。
  • 换句话说,像Parent, child1, .... child(n)?

标签: sql sql-server-2008 tsql recursive-query


【解决方案1】:

出于演示目的,您可以使用以下代码,基于我以前的帖子。
SQL Challenge/Puzzle: How to create an ASCII art hierarchy tree with an SQL query?

with        h (id,pid)
            as
            (
                select      [Article-Material2] as id
                           ,[Article-Material1] as pid

                from        mytable

                where       [Article-Material2] is not null

                union all

                select      distinct
                            [Article-Material1]     as id
                           ,null                    as pid

                from        mytable

                where       [Article-Material1] not in (select [Article-Material2] from mytable where [Article-Material2] is not null)
            )       

           ,last_sibling (id)
            as
            (
                select      max (id)
                from        h
                group by    pid
            )

           ,tree (id,branch,path)
            as
            (
                select      h.id
                           ,cast ('' as varchar(max))
                           ,cast (h.id as varchar(max))

                from        h

                where       h.pid is null

                union all

                select      h.id
                           ,t.branch + case when (select 1 from last_sibling ls where ls.id = t.id) = 1 then ' ' else '|' end + '    '
                           ,t.path + '_' + h.id

                from                    tree            t

                            join        h

                            on          h.pid =
                                        t.id
            )

           ,vertical_space (n)
            as
            (
                select      1

                union all

                select      vs.n + 1
                from        vertical_space  vs
                where       vs.n < 2
            )

select      t.branch + case vs.n when 1 then '|____' + ' ' + t.id else '|' end

from                    tree            t

            cross join  vertical_space  vs

order by    t.path
           ,vs.n desc

option      (maxrecursion 0)
;

|
|____ article001
|    |
|    |____ article002
|    |    |
|    |    |____ article004
|    |    |    |
|    |    |    |____ material004
|    |    |
|    |    |____ material002
|    |
|    |____ article003
|    |    |
|    |    |____ material003
|    |
|    |____ material001
|
|____ article005
     |
     |____ article010
     |    |
     |    |____ material005
     |
     |____ article011
     |    |
     |    |____ article012
     |    |    |
     |    |    |____ material002
     |    |    |
     |    |    |____ material007
     |    |
     |    |____ material004
     |    |
     |    |____ material006
     |
     |____ material001

【讨论】:

    【解决方案2】:
    Declare @YourTable table ([Article-Material1] varchar(25),[Article-Material2] varchar(25))
    Insert Into @YourTable values
    ('article001','article002'),
    ('article001','article003'),
    ('article001','material001'),
    ('material001',null),
    ('article002','article004'),
    ('article002','material002'),
    ('material002',null),
    ('article003','material003'),
    ('material003',null),
    ('article004','material004'),
    ('material004',null),
    ('article005','article010'),
    ('article005','article011'),
    ('article005','material001'),
    ('article010','material005'),
    ('material005',null),
    ('article011','article012'),
    ('article011','material004'),
    ('article011','material006'),
    ('material006',null),
    ('article012','material002'),
    ('article012','material007'),
    ('material007',null)
    
    
    Declare @Top    varchar(25) = null       --<<  Sets top of Hier Try 'article002' 
    Declare @Nest   varchar(25) = '|-----'  --<<  Optional: Added for readability
    
    ;with  cte0 as (
           Select ID=[Article-Material2]
                 ,Pt=[Article-Material1]
           From   @YourTable
           Where  [Article-Material2] is not null
           Union All
           Select ID=[Article-Material1]
                 ,Pt=null
           From   @YourTable
           Where  [Article-Material1] not in (Select [Article-Material2] from @YourTable where [Article-Material2] is not null) )               
    ,     cteP as (
          Select Distinct
                 Seq  = cast(ID as varchar(500))
                ,ID
                ,Pt
                ,Lvl=1
          From   cte0 
          Where  IsNull(@Top,'X') = case when @Top is null then isnull(Pt,'X') else ID end
          Union  All
          Select Seq  = cast(p.Seq+'.'+r.ID+r.Pt as varchar(500))
                ,r.ID
                ,r.Pt
                ,p.Lvl+1
          From   cte0 r
          Join   cteP p on r.Pt = p.ID and r.Pt=p.ID)
         ,cteR1 as (Select *,R1=Row_Number() over (Order By Seq) From cteP )
         ,cteR2 as (Select A.Seq,A.ID,R2=Max(B.R1) From cteR1 A Join cteR1 B on (B.Seq like A.Seq+'%') Group By A.Seq,A.ID )
    Select Distinct
           A.R1  
          ,B.R2
          ,A.ID
          ,A.Pt
          ,A.Lvl
          ,Title = Replicate(@Nest,A.Lvl-1) + A.ID
     From cteR1 A
     Join cteR2 B on A.Seq=B.Seq where R2>=R1
     Order By A.R1
    

    退货

    现在,只是为了好玩,将 @Top 设置为 'article002',你会得到:

    【讨论】:

    • 再次感谢您。这对我帮助很大。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-02
    • 1970-01-01
    相关资源
    最近更新 更多