我有一个表有两列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来分解列表。
答案 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