如何使用TSQL分解此树?

时间:2017-08-16 21:26:09

标签: sql-server tsql

我有一个表有两列I1,I2(两个索引到另一个表中)并组成一个树。

I1  I2
1   3
4   6
2   5
3   7
6   9
8   11

我希望从列表中删除:

Group Num
1      1
1      3
1      7
2      4
2      6
2      9    
3      8
3     11
4      2
4      5

现在我使用代码继续搜索匹配项,直到运行中的匹配数与上次运行的匹配数相同。有没有办法使用TSQL来分解列表。

1 个答案:

答案 0 :(得分:2)

我删除了我以前的答案;我现在完全明白你要做什么了。如果您的"树"该解决方案将有效。最多可达3级。如果你插入了值(7,20),我们需要添加一个额外的LEFT JOIN和额外的UNION ALL。

使用recursive CTE也可以更干净地完成此操作但是,如果您处理固定数量的级别,此技术将表现更好。

-- your table
use tempdb
go
if object_id('dbo.mytable') is not null drop table dbo.mytable;
create table dbo.mytable
(
  I1 int not null,
  I2 int not null,
    constraint pk_cl_mytable primary key clustered(I1,I2)
);
go
insert dbo.mytable values (1,3),(4,6),(2,5),(3,7),(6,9),(8,11);
go

-- solution
WITH flatten AS
(
  SELECT 
    L1 = t1.I1, 
    L2 = t1.I2,
    L3 = t2.I2
  FROM dbo.mytable t1
  LEFT JOIN dbo.mytable t2 ON t1.I2 = t2.I1
),
setGroups AS
(
  SELECT [group] = row_number() over (order by L1), * 
  FROM flatten
  WHERE L1 NOT IN (SELECT L2 FROM flatten)
)
SELECT [group], L1 FROM setGroups
UNION ALL 
SELECT [group], L2 FROM setGroups WHERE L2 IS NOT NULL
UNION ALL 
SELECT [group], L3 FROM setGroups WHERE L3 IS NOT NULL
ORDER BY [group]; -- not required, including for presentation purposes

结果:

group                L1
-------------------- -----------
1                    1
1                    3
1                    7
2                    5
2                    2
3                    4
3                    6
3                    9
4                    11
4                    8

如果需要,您可以在层次结构中包含每个节点的级别,方法是包含一个静态lvl值来调出每个节点的级别:

WITH flatten AS
(
  SELECT 
    L1 = t1.I1, 
    L2 = t1.I2,
    L3 = t2.I2
  FROM dbo.mytable t1
  LEFT JOIN dbo.mytable t2 ON t1.I2 = t2.I1
),
setGroups AS
(
  SELECT [group] = row_number() over (order by L1), * 
  FROM flatten
  WHERE L1 NOT IN (SELECT L2 FROM flatten)
)
SELECT [group], L1, lvl = 1 FROM setGroups
UNION ALL 
SELECT [group], L2, lvl = 2 FROM setGroups WHERE L2 IS NOT NULL
UNION ALL 
SELECT [group], L3, lvl = 3 FROM setGroups WHERE L3 IS NOT NULL
ORDER BY [group], lvl; -- not required, including for presentation purposes

结果:

group    L1  lvl 
-------- --- ----
1        1   1
1        3   2
1        7   3
2        2   1
2        5   2
3        4   1
3        6   2
3        9   3
4        8   1
4        11  2