【问题标题】:SQL Server to show a data tree in a specific formatSQL Server 以特定格式显示数据树
【发布时间】:2011-03-15 16:12:49
【问题描述】:

我们有一张这样的表(简化版):

项目:

Itemid   Itemname    Itemfatherid
itemA    theitemA    null
itemB    theitemB    null
itemC    theitemC    itemA
itemD    theitemD    itemA
itemE    theitemE    itemC
itemF    theitemF    itemE
itemG    theitemG    itemD

我们需要一个给出以下结果/格式的 sql 查询:(更正的版本)

Col1    Col2    Col3    Col4
itemA   itemC   itemE   itemF
itemA   itemD   itemG   NULL
itemB   NULL    NULL    NULL

我们的 ERP 会采用此结果并将其转换为如下所示的树形控件:

-itemA
    -itemC
        -itemE
            itemF
    -itemD
        itemG
itemB

树的层级不是固定的,所以列数必须是动态的...

CTE 有一些方法,但我们还没有找到解决方案:S

http://www.sqlservercurry.com/2009/06/simple-family-tree-query-using.html

我们还需要知道树的深度(将它传递给 GridControl...),在这个例子中它将是 3(它需要最大的父级别数 --> -itemA -itemC -itemE)

【问题讨论】:

  • 动态列需要动态 SQL。在 TSQL 中不是特别简单。你的代码不能以行格式处理它吗?
  • 嗯,它是一个 sql 查询,作为 c# 中的字符串,在控件调用中传递,如 Grid.Render("sql");所以一些逻辑可以在 c# 中实现,但我们更喜欢在查询本身中处理它......

标签: sql-server sql-server-2008 formatting tree hierarchy


【解决方案1】:

样本表

create table so1 (Itemid varchar(100), Itemname varchar(100), Itemfatherid varchar(100))
insert so1 select
'itemA','theitemA',null union all select
'itemB','theitemB',null union all select
'itemC','theitemC','itemA' union all select
'itemD','theitemD','itemA' union all select
'itemE','theitemE','itemC' union all select
'itemF','theitemF','itemE' union all select
'itemG','theitemG','itemD'

查询

if OBJECT_ID('tempdb..#tmp') is not null drop table #tmp
;
create table #tmp (
    uniqueid uniqueidentifier not null,
    level int not null,
    itemid varchar(100) null,
    primary key clustered(uniqueid, level)
)
;with cte(level, itemid, parentid, uniqueid) as
(
    select 1, itemid, itemfatherid, NEWID()
    from so1
    where not exists (select * from so1 k where k.itemfatherid=so1.itemid)
    union all
    select cte.level+1, t.itemid, t.itemfatherid, cte.uniqueid
    from cte
    inner join so1 t on t.Itemid = cte.parentid
)
insert #tmp (uniqueid, level, itemid)
select uniqueid, level, itemid
from cte
option (maxrecursion 1000) -- as required
;
;with tmp as (
    select *, newlevel = ROW_NUMBER() over (partition by uniqueid order by level desc)
    from #tmp)
update tmp
set level = newlevel
;
declare @sql nvarchar(max), @columns nvarchar(max)
;
set @sql = CONVERT(nvarchar(max), (
    select number [data()]
    from master..spt_values
    where type='P' and number between 1 and (select MAX(level) from #tmp)
    order by 1
    for xml path('a')))
select @sql = stuff(replace(replace(@sql,'</a><a>','],['),'</a>',']'),1,3,'[')
select @sql = '
select ' + @sql + '
from #tmp
pivot (max(itemid) for level in (' + @sql + ')) v
order by ' + @sql
exec (@sql)

输出

1       2       3       4
itemA   itemC   itemE   itemF
itemA   itemD   itemG   NULL
itemB   NULL    NULL    NULL

【讨论】:

  • 相当令人印象深刻的逻辑......不幸的是,格式与我们提供的示例不同(抱歉,我们今天发现我们写错了)如果您不介意花时间再次检查并更改相应地,遮阳篷......如果没有问题,它就足够有用了...... :)
  • @ase69s - 更新了一次更改,添加了 WHERE 子句以仅从叶节点开始
  • 像一个魅力一样工作,只有一件事,如何获得最大父母数量的查询(之前添加在问题的末尾)
猜你喜欢
  • 1970-01-01
  • 2013-07-02
  • 1970-01-01
  • 1970-01-01
  • 2015-06-07
  • 1970-01-01
  • 2020-02-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多