SQL识别相关行(Hierarchal)

时间:2013-12-17 10:19:53

标签: sql

我需要使用两个字段来识别彼此相关的行,在某种程度上它是一个层次结构,但不能让CTE工作。

这是一张简化的表格:

CREATE TABLE [dbo].[LinkedRows](
    [ID] [int] NULL,
    [COL1] [nvarchar](50) NULL,
    [COL2] [nvarchar](50) NULL,
    [LINK] [int] NULL
) ON [PRIMARY]

以下是一些数据:

INSERT INTO dbo.LinkedRows (ID, COL1, COL2) VALUES (1, 'A','B')
INSERT INTO dbo.LinkedRows (ID, COL1, COL2) VALUES (2, 'C','B')
INSERT INTO dbo.LinkedRows (ID, COL1, COL2) VALUES (3, 'A','D')
INSERT INTO dbo.LinkedRows (ID, COL1, COL2) VALUES (4, 'D','A')
INSERT INTO dbo.LinkedRows (ID, COL1, COL2) VALUES (5, 'B','A')
INSERT INTO dbo.LinkedRows (ID, COL1, COL2) VALUES (6, 'E','C')
INSERT INTO dbo.LinkedRows (ID, COL1, COL2) VALUES (7, 'B','C')
INSERT INTO dbo.LinkedRows (ID, COL1, COL2) VALUES (8, 'C','E')
INSERT INTO dbo.LinkedRows (ID, COL1, COL2) VALUES (9, 'F','G')
INSERT INTO dbo.LinkedRows (ID, COL1, COL2) VALUES (10, 'G','H')

这是我试图确定的:

ID      COL1    COL2    linked
1       A       B       1
2       C       B       1
3       A       D       1
4       D       A       1
5       B       A       1
6       E       C       1
7       B       C       1
8       C       E       1
9       F       G       2
10      G       H       2

第1行和第2行在COL2中都有B,因此A,B和C都相互关联,并且给出了相同的链接号(ID)。 在第3行和第4行中,我们有A,D和D,A,因为第5行中有B,A的组合,D可以链接到B到A,所以现在我们可以将A,B,C,D连接在一起。 在第6行和第8行,我们有E,C和C,E,所以我们现在可以将A,B,C,D,E连接在一起。 第7行与第2行正好相反。 在第9行,我们有F,G因为我们无法从这些中的任何一个链接到A,B,C,D,E,所以创建了另一个链接组。 在第10行,我们有G,H,它可以通过G链接到连接的组2,即F,G,H是相关的。

非常感谢任何帮助或建议。

此致 CM

1 个答案:

答案 0 :(得分:1)

我不确定这可以用CTE递归地完成。

但是,由于表中已经有LINK字段,因此可以使用SQL代码填写此字段。每次更改数据时都必须运行代码:

-- Reset LINK
UPDATE LinkedRows SET LINK = NULL;

-- Declare variables
DECLARE @LinkCounter int;
DECLARE @myID int;
DECLARE @myCOL1 nvarchar(50);
DECLARE @myCOL2 nvarchar(50);
DECLARE @myLINK1 int;
DECLARE @myLINK2 int;
-- Init group counter
SET @LinkCounter = 0;

DECLARE RowCursor CURSOR FOR 
SELECT ID, COL1, COL2 FROM LinkedRows ORDER BY ID;

OPEN RowCursor;

-- Run through all records
FETCH NEXT FROM RowCursor INTO @myID, @myCOL1, @myCOL2;
WHILE @@FETCH_STATUS = 0 -- More records
    BEGIN
        DECLARE LinkCursor CURSOR FOR SELECT DISTINCT(LINK) FROM LinkedRows WHERE (COL1 = @myCOL1 OR COL1 = @myCOL2 OR COL2 = @myCOL1 OR COL2 = @myCOL2) AND NOT LINK IS NULL;
        OPEN LinkCursor;
        FETCH NEXT FROM LinkCursor INTO @myLINK1;
        IF @@FETCH_STATUS = 0 -- At least one record
            BEGIN
                FETCH NEXT FROM LinkCursor INTO @myLINK2;
                IF @@FETCH_STATUS = 0 -- Two records present - Link two groups
                    BEGIN
                        -- SELECT 'Link', @myLINK1, @myLINK2; -- Debug
                        -- Join the groups - use the first LINK id
                        UPDATE LinkedRows SET LINK = @myLINK1 WHERE LINK = @myLINK2;
                        -- Add the new record to the group
                        UPDATE LinkedRows SET LINK = @myLINK1 WHERE ID = @myID;
                    END;
                ELSE -- Only one group - assign new record to existing group
                    BEGIN
                        -- SELECT 'Assign', @myLINK1; -- Debug
                        UPDATE LinkedRows SET LINK = @myLINK1 WHERE ID = @myID;
                    END;
            END;
        ELSE -- New group
            BEGIN
                SET @LinkCounter = @LinkCounter + 1;
                -- SELECT 'New', @LinkCounter;
                UPDATE LinkedRows SET LINK = @LinkCounter WHERE ID = @myID;
            END;
        CLOSE LinkCursor
        DEALLOCATE LinkCursor
        -- Get next record
        FETCH NEXT FROM RowCursor INTO  @myID, @myCOL1, @myCOL2;
    END;
CLOSE RowCursor;
DEALLOCATE RowCursor;

现在LINK字段将包含链接组。

已编辑更新了代码,以处理通过链接记录加入两个组的情况。