使用TSQL遍历大型网络

时间:2013-02-05 10:28:39

标签: sql sql-server tsql

我有一个包含个人和一些细节的大型数据集。该数据集包含大量重复项,并且大量记录基于它们的一个特征彼此“相关”。为确保链接正确的记录,3个功能中的2个匹配将被计为链接。每个人都需要链接到所有可能的记录,并且每个记录都将被分配一个clusterId。

我有以下数据集结构:

+--+----+----+----+
|id|col1|col2|col3|
+--+----+----+----+
|1 |A   |B   |C   |
+--+----+----+----+
|2 |A   |B   |D   |
+--+----+----+----+
|3 |A   |Z   |D   |
+--+----+----+----+

Id 1将链接到id 2(因为col1和col2是相同的),id 2将链接到id 3(因为col1和col3是相同的)。链接id 1和2为这个“集群”增加了一些信息,在建立了链接之后,id 3应属于该集群。

数据集非常大(2800万条记录),我不知道这会让我在合理的时间范围内建立这些关系。

任何想法解决这个问题的最快捷,最优雅的方式是什么?

1 个答案:

答案 0 :(得分:0)

有了那么多数据,创建关系可能会很慢,但是如果您的列被编入索引并且您有一个快速的服务器,那么它可能不会太糟糕。创建一个表来存储关系。这个SQL应该填充关系。

CREATE TABLE RelationshipTable
    ([id1] int, [id2] int,[cluster] int);   

INSERT INTO RelationshipTable
    SELECT a.id,b.id,NULL
    FROM TestTable a
    LEFT JOIN TestTable b ON a.id<>b.id AND (
        (
                    ((a.col1 is null and b.col1 is null) or a.col1=b.col1)
                and ((a.col2 is null and b.col2 is null) or a.col2=b.col2)
        )
        OR
        (
                    ((a.col1 is null and b.col1 is null) or a.col1=b.col1)
                and ((a.col3 is null and b.col3 is null) or a.col3=b.col3)
        )
        OR
        (
                    ((a.col2 is null and b.col2 is null) or a.col2=b.col2)
                and ((a.col3 is null and b.col3 is null) or a.col3=b.col3)
        )
    )

DECLARE @UpdateId INT
DECLARE @ClusterId INT
SET @ClusterId=0

WHILE EXISTS(
    SELECT *
    FROM RelationshipTable
    WHERE [cluster] IS NULL
)
BEGIN
  SET @ClusterId=@ClusterId+1

  SELECT
    @UpdateId=[id1]
  FROM RelationshipTable
  WHERE [cluster] IS NULL

  UPDATE RelationshipTable
  SET [cluster]=@ClusterId
  WHERE ID1=@UpdateId
  OR ID2=@UpdateId

  WHILE @@Rowcount>0
  BEGIN
    UPDATE RelationshipTable
    SET [cluster]=@ClusterId
    WHERE [cluster] IS NULL
    AND
    (
      ID1 IN (
           SELECT ID1
           FROM RelationshipTable
           WHERE [cluster]=@ClusterId
           UNION
           SELECT ID2
           FROM RelationshipTable
           WHERE [cluster]=@ClusterId
      )
      OR ID2 IN (
           SELECT ID1
           FROM RelationshipTable
           WHERE [cluster]=@ClusterId
           UNION
           SELECT ID2
           FROM RelationshipTable
           WHERE [cluster]=@ClusterId
      )
    )
  END
END

select * from RelationshipTable