我有一个记录增加的表。它包含一些列,包括ID1,ID2。我想插入一列以这种方式对这些记录进行分类:
例如,如果id1 = 1与id2 = 2相关,则属于一个类别
如果id1 = 3与id2 = 2相关,则同一类别中的所有三个id 1、2、3组
Pk | id1 | id2 | category
--------+---------+---------+-----------
1 | 1111 | 2222 | 1
2 | 2222 | 3333 | 1
3 | 3333 | 1111 | 1
4 | 4444 | 5555 | 1
5 | 2222 | 1111 | 1
6 | 5555 | 1111 | 1
7 | 6666 | 8888 | 2
8 | 7777 | 9999 | 3
如果有任何新记录添加到表中,它将得到一个组并更新旧组。例如,如果新记录如下所示,则将第7行的类别更改为1
Pk | id1 | id2 | category
--------+---------+---------+-----------
7 | 6666 | 8888 | 1
8 | 7777 | 9999 | 3
9 | 8888 | 1111 | 1
或代替在此表中插入列,而创建另一个具有id和category的表,以实现每个id的类别。
通过这种方式,我想了解不同ID之间的网络。
答案 0 :(得分:1)
使用CTE,一般的图形行走有点痛苦-但有可能。确实没有其他选择。
在SQL Server中,您可以维护已访问节点的列表。这样可以防止无限递归。不幸的是,该列表是使用字符串存储的。
因此,这将计算类别:
with t as (
select v.*
from (values (1, 1111, 2222),
(2, 2222, 3333),
(3, 3333, 1111),
(4, 4444, 5555),
(5, 2222, 1111),
(6, 5555, 1111),
(7, 6666, 8888),
(8, 7777, 9999)
) v(pk, id1, id2)
),
cte as (
select pk, id1, id1 as id2, convert(varchar(max), concat(',', id1, ',')) as visited
from t
union all
select cte.pk, cte.id1, t.id2, convert(varchar(max), concat(visited, t.id2, ','))
from cte join
t
on cte.id2 = t.id1
where cte.visited not like concat('%,', t.id2, ',%')
union all
select cte.pk, cte.id1, t.id1, convert(varchar(max), concat(visited, t.id1, ','))
from cte join
t
on cte.id2 = t.id2
where cte.visited not like concat('%,', t.id1, ',%')
)
select pk, id1, min(id2), dense_rank() over (order by min(id2))
from cte
group by pk, id1;
您可以修改此代码以进行更新(通过主键上的联接)。
您还可以将其合并到触发器或应用程序中,以在添加新边时调整类别。
但是,您应该修改数据结构。您具有图形数据结构,因此应该有一个ID表和一个边表。 类别表示断开的子图,应应用于节点而不是边。
Here是具有以上代码的db <>小提琴。
答案 1 :(得分:0)
这种方式对我有帮助 请为您自己定制:
declare @t table(id int,parentId int,name varchar(20))
insert @t select 1, 0, 'Category1'
insert @t select 2, 0, 'Category2'
insert @t select 3, 1, 'Category3'
insert @t select 4 , 2, 'Category4'
insert @t select 5 , 1, 'Category5'
insert @t select 6 , 2, 'Category6'
insert @t select 7 , 3, 'Category7'
;
WITH tree (id, parentid, level, name, rn) as
(
SELECT id, parentid, 0 as level, name,
convert(varchar(max),right(row_number() over (order by id),10)) rn
FROM @t
WHERE parentid = 0
UNION ALL
SELECT c2.id, c2.parentid, tree.level + 1, c2.name,
rn
FROM @t c2
INNER JOIN tree ON tree.id = c2.parentid
)
SELECT *
FROM tree
order by RN