如何在无向循环图中对所有链接对象进行分组

Arc*_*rus 5 sql-server cte recursive

我有一张桌子,上面有客户及其联合客户。例如,客户 1 有一个联合客户 2。客户 1 也是客户 3 的联合客户。

我正在尝试将所有链接的客户分组并为他们分配相同的 GroupCustNo。下表1-2相连,3-1相连。所以2-3也有联系。因此,下表中从 1 到 8 的所有客户都相互关联,并且将具有相同的 GroupCustNo。

 tbl_GroupCustomers:

CustNo   JtCustNo  GroupCustNo    
---      -------     ------   
1           2          null
2           null       null
3           1          null
4           1          null
4           5          null
5           6          null
5           7          null
6           null       null
7           null       null
8           5          null
Run Code Online (Sandbox Code Playgroud)

我写的递归存储过程如下。我在每个 CustNo 的 while 循环中调用它:

exec usp_UpdateGroupCustomerNo 1, 1 存储过程对大多数客户成功运行但吐了

某些客户的递归限制达到 32 错误。这些客户拥有许多联合客户,同时也是其他客户的联合客户。

似乎递归在这里不起作用,我对如何进行感到茫然。请让我知道是否有任何替代方法可以解决此问题。

CREATE PROCEDURE [dbo].[usp_UpdateGroupCustomerNo]
     @MainCustNo int, @GrpNo int
AS 
    declare @JtCustNo int; declare @MainCustNo2 int;

if exists(select 1 from tbl_GroupCustomer 
          where CustNo = @MainCustNo and groupcustomernumber is null)
begin    
    update tbl_GroupCustomer 
    set groupcustomernumber = @grpno 
    where CustNo = @MainCustNo 
      and groupcustomernumber is null

    DECLARE db_cursor CURSOR LOCAL FOR  
         select JtCustNo 
         from tbl_GroupCustomer 
         where CustNo = @MainCustNo and JtCustNo is not null

    OPEN db_cursor   

    FETCH NEXT FROM db_cursor INTO @JtCustNo   

    WHILE @@FETCH_STATUS = 0   
    BEGIN   
        select @JtCustNo as JtCustNo      

        exec usp_UpdateGroupCustomerNo @JtCustNo, @GrpNo

        DECLARE db_cursor2 CURSOR LOCAL FOR  
            select CustNo 
            from tbl_GroupCustomer 
            where JtCustNo = @JtCustNo 
              and groupcustomernumber is null

        OPEN db_cursor2

        FETCH NEXT FROM db_cursor2 INTO @MainCustNo2   

        WHILE @@FETCH_STATUS = 0   
        BEGIN   
            if exists(select 1 from tbl_GroupCustomer 
                      where CustNo = @MainCustNo2 
                        and groupcustomernumber is null)
            begin     
                exec usp_UpdateGroupCustomerNo @MainCustNo2, @GrpNo
            end

            FETCH NEXT FROM db_cursor INTO @MainCustNo2   
        END   

        CLOSE db_cursor2   
        DEALLOCATE db_cursor2

        FETCH NEXT FROM db_cursor INTO @JtCustNo   
END  

CLOSE db_cursor   
DEALLOCATE db_cursor
Run Code Online (Sandbox Code Playgroud)

结尾

For*_*est 1

此答案假设您无法通过OPTION (MAXRECURSION 0)在过程中的某个位置使用来删除递归限制。

我花了一段时间尝试递归解决方案,但无论我尝试什么,我都不能保证它会小于递归限制 - 我总是可以构建一个需要更多迭代的链。

因此,这是一个简单的循环解决方案,以及用于测试的 DDL:

/*
IF OBJECT_ID('tempdb..#tbl_GroupCustomers') IS NOT NULL
DROP TABLE #tbl_GroupCustomers

CREATE TABLE #tbl_GroupCustomers
(CustNo int,
JtCustNo int,
GroupCustNo int)

INSERT #tbl_GroupCustomers
(CustNo, JtCustNo)
VALUES
(1,2),
(2,NULL),
(3,1),
(4,1),
(4,5),
(5,3),
(6,7),
(7,8),
(8,6),
(9,null)

SELECT *
FROM #tbl_GroupCustomers
*/


DECLARE @GN int = 1
DECLARE @seedCust int
DECLARE @count1 int, @count2 int

--Outer loop: iterate group numbers
WHILE EXISTS(SELECT * FROM #tbl_GroupCustomers WHERE GroupCustNo IS NULL)
BEGIN
--Find next ungrouped customer
SET @seedCust = (SELECT TOP 1 CustNo FROM #tbl_GroupCustomers WHERE GroupCustNo IS NULL)
--reset counts
SET @count1 = 0
SET @count2 = 1

--Start with a customer
--Give that customer a Group number
UPDATE GC
SET GroupCustNo = @GN
FROM #tbl_GroupCustomers GC
WHERE CustNo = @seedCust

    --Inner loop
    WHILE @count1 <> @count2
    BEGIN

    --How many records?
    SELECT @count1 = COUNT(*) FROM #tbl_GroupCustomers WHERE GroupCustNo = @GN

    --Give all linked records the same GN
    UPDATE GC2
    SET GC2.GroupCustNo = @GN
    FROM (SELECT CustNo, JtCustNo
        FROM #tbl_GroupCustomers
        WHERE GroupCustNo = @GN
        ) GC1
    INNER JOIN #tbl_GroupCustomers GC2
    ON GC1.CustNo = GC2.JtCustNo
    OR GC1.JtCustNo = GC2.CustNo
    OR GC1.CustNo = GC2.CustNo
    OR GC1.JtCustNo = GC2.JtCustNo

    --How many records? If same, it ends loop
    SELECT @count2 = COUNT(*) FROM #tbl_GroupCustomers WHERE GroupCustNo = @GN
    END

SET @GN +=1
END
Run Code Online (Sandbox Code Playgroud)

起始表:

CustNo      JtCustNo    GroupCustNo
----------- ----------- -----------
1           2           NULL
2           NULL        NULL
3           1           NULL
4           1           NULL
4           5           NULL
5           3           NULL
6           7           NULL
7           8           NULL
8           6           NULL
9           NULL        NULL
Run Code Online (Sandbox Code Playgroud)

结果:

CustNo      JtCustNo    GroupCustNo
----------- ----------- -----------
1           2           1
2           NULL        1
3           1           1
4           1           1
4           5           1
5           3           1
6           7           2
7           8           2
8           6           2
9           NULL        3
Run Code Online (Sandbox Code Playgroud)