在SQL中对表的记录进行分类?

时间:2019-01-01 05:35:58

标签: sql sql-server

我有一个记录增加的表。它包含一些列,包括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之间的网络。

2 个答案:

答案 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
相关问题