在SQL

时间:2016-01-28 21:06:50

标签: sql sql-server hierarchical-data recursive-query

您如何编写一个递归SQL查询,将不同级别的层次关系显示为单个结果?

我的数据库中有一个表(Container),它与自身有层次关系(任何容器都可以有很多内部容器)。我正在尝试创建一个视图,显示每个容器的所有外部(不仅仅是它的直接外部)以及内部容器的深度。例如:

如果我的Container表中包含以下记录:

  • Id:1 outerId:null
  • Id:2 outerId:1
  • Id:3 outerId:1
  • Id:4 outerId:2
  • Id:5 outerid:4

我希望视图显示:

  • innerId:2 outerId:1 lvl:1
  • innerId:3 outerId:1 lvl:1
  • innerId:4 outerId:1 lvl:2
  • innerId:4 outerId:2 lvl:1
  • innerId:5 outerId:1 lvl:3
  • innerId:5 outerId:2 lvl:2
  • innerId:5 outerId:4 lvl:4

不是

  • Id:2路径:1
  • Id:3路径:1
  • Id:4路径:1,2
  • Id:5路径:1,2,4

基本上,我希望能够通过执行:select innerId from v_MyView where outerId = @outer_id找出特定容器内部容器的内容,并通过执行以下内容找出特定容器所在的容器:select outerId from v_MyView where innerId = @inner_id

更新

我正在使用SQL Server 2012,而且我对递归CTE非常熟悉。我遇到的问题不是我不知道如何编写递归CTE,而是我需要输出在多行而不是视图中的连接字段。

这就是我已经拥有的:

with MYCTE as
(
    select 
         Id, 
         Cast(null as varchar(max)) as cntr_path,
         0 as lvl
      from Container
      where Container.outerId is null
    union all
    select 
        Container.Id,
        IsNull(cntr_path + ',','') + '[' + cast(Container.outerId as varchar(max)) + ']',
        lvl + 1
      from Container join MYCTE 
        on Container.outerId = MYCTE.Id
)
select * from MYCTE where cntr_path is not null

但是每个内部容器只产生一行。我想要的是每个外部容器每个内部容器一行

我想描述我想要的视图的最佳方式是将每个外部容器与其内部容器相关联的“链接表” - “outerId”和“innerId”都像外键一样(两者都指向容器中的Id。

2 个答案:

答案 0 :(得分:1)

如果您使用的是SQL Server,请查看此Microsoft link。它详细介绍了递归公用表表达式。

在Oracle中,这是一个描述Hierarchical Queries的链接。

MySQL hierarchical queries

文章中给出的例子将为您解决问题提供必要的垫脚石。

答案 1 :(得分:0)

在睡了一会儿之后,我意识到我错误地识别了我的递归CTE的锚点。而不是最外面的容器是我的锚(如在我的更新示例中),锚应该是每个具有外部的容器:

select 
     Id as InnerId, 
     Container.outerId as OuterId
     1 as lvl
  from Container

这是我CTE的递归部分:

union all
select 
    MYCTE.InnerId,
    Container.OuterId
    lvl + 1
  from Container join MYCTE 
    on Container.Id = MYCTE.OuterId
  where Container.OuterId is not null