TSQL从扁平结构创建不规则的层次结构

时间:2013-09-20 06:37:58

标签: sql sql-server tsql sql-server-2012

考虑下表:

declare @table as table (
    GL_Group_Code   varchar(8),
    GL_Branch_Code  varchar(8),
    Account_Number  varchar(4),
    GL_Centre_Number    varchar(6)
)

insert into @table
select  '0100', '0110', '1200', 'S10118' union
select  '0100', '0110', '1580', 'S16053' union
select  '0200', '0210', '2050', '200049' union
select  '0200', '0210', '2050', '782844'

期望的结果是四个源列中的父子关系:

declare @table_hier as table (
    Parent_ID   varchar(8),
    Item_ID     varchar(8)
)

使用第1,2,3,4列的关系顺序,源表中第一行的结果如下所示:

null 0100
0100 0110
0110 1200
1200 S10118 

第二行是:

null 0100
0100 0110
0110 1580
1580 S16053

关系顺序可能有所不同:1,2,4,3或3,4或1,3,4

我正在考虑递归CTE,但是在周五晚些时候,我可以做很少的帮助。

2 个答案:

答案 0 :(得分:0)

尝试这样的事情

declare @table as table (
    GL_Group_Code   varchar(8),
    GL_Branch_Code  varchar(8),
    Account_Number  varchar(4),
    GL_Centre_Number    varchar(6)
)

insert into @table
select  '0100', '0110', '1200', 'S10118' union
select  '0100', '0110', '1580', 'S16053' union
select  '0200', '0210', '2050', '200049' union
select  '0200', '0210', '2050', '782844'

declare @table_hier as table (
    Parent_ID   varchar(8),
    Item_ID     varchar(8)
)

DECLARE @RelatonShip VARCHAR(4)

SET @RelatonShip = '134'

IF @RelatonShip = '1234'
BEGIN
    INSERT INTO @table_hier ( Parent_ID, Item_ID )
    SELECT GL_Group_Code, GL_Branch_Code FROM @table 
    UNION ALL SELECT GL_Branch_Code, Account_Number FROM @Table
    UNION ALL SELECT Account_Number, GL_Centre_Number FROM @table
END
IF @RelatonShip = '1243'
BEGIN
    INSERT INTO @table_hier ( Parent_ID, Item_ID )
    SELECT GL_Group_Code, GL_Branch_Code FROM @table 
    UNION ALL SELECT GL_Branch_Code, GL_Centre_Number FROM @Table
    UNION ALL SELECT GL_Centre_Number, Account_Number FROM @table
END
IF @RelatonShip = '34'
BEGIN
    INSERT INTO @table_hier ( Parent_ID, Item_ID )
    SELECT Account_Number, GL_Centre_Number FROM @table
END
IF @RelatonShip = '134'
BEGIN
    INSERT INTO @table_hier ( Parent_ID, Item_ID )
    SELECT GL_Group_Code, Account_Number FROM @table 
    UNION ALL SELECT Account_Number, GL_Centre_Number FROM @table
END

SELECT * FROM @table_hier

答案 1 :(得分:0)

如果你的表中有id并使用表变量存储你想要的列,你可以这样做:

declare @ord table (id int)

insert into @ord
values (1), (2), (4)

;with cte as (
    select
        t.id,
        c.value,
        row_number() over(partition by t.id order by c.id) as rn
    from @table as t
        cross apply (
            values
                (1, t.GL_Group_Code),
                (2, t.GL_Branch_Code),
                (3, t.Account_Number),
                (4, t.GL_Centre_Number)
        ) as c(id, value)
    where
        exists (select * from @ord as o where o.id = c.id)
)
insert into @table_hier
select
    c1.value as Parent_ID, c2.value as Item_ID
from cte as c1
    inner join cte as c2 on c2.rn = c1.rn + 1 and c2.id = c1.id
order by c1.rn

insert into @table_hier
select null, t.Parent_ID
from @table_hier as t
where
    not exists
    (
         select *
         from @table_hier as t2
         where t2.Item_ID = t.Parent_ID
    )


select * from @table_hier

<强> sql fiddle demo

或者,如果您可以将数据存储在表或临时表中,则可以使用动态SQL解决方案:

declare @ord table (id int)
declare @stmt nvarchar(max)

insert into @ord
values (1), (2), (4)

;with cte as (
select c.name, row_number() over(order by c.colid) as rn
from sys.syscolumns as c
where
    c.id = object_id('dbo.table1') and
    exists (select * from @ord as o where o.id = c.colid)
)
select @stmt =
    isnull(@stmt + ', ', '') + 
    '(' + c1.name + ', ' + c2.name + ')'
from cte as c1
    inner join cte as c2 on c2.rn = c1.rn + 1
order by c1.rn

select @stmt = '
    insert into table_hier1
    select C.Parent_ID, C.Item_ID
    from table1 as t
        cross apply (
            values ' + @stmt + '
        ) as C(Parent_ID, Item_ID)
'

exec sp_executesql
    @stmt = @stmt

insert into table_hier1
select null, t.Parent_ID
from table_hier1 as t
where
    not exists
    (
         select *
         from table_hier1 as t2
          where t2.Item_ID = t.Parent_ID
    )

select * from table_hier1

<强> sql fiddle demo