SQL中的递归CTE - 如何避免重复结果?

时间:2017-06-09 13:37:43

标签: sql-server tsql recursion common-table-expression

在我的SQL数据模型中,我有一个关联表,用于将客户与客户帐户相关联。一个帐户可以由多个客户持有,一个客户可以拥有多个帐户。

我想找到客户之间的关系,同时还要显示帐户。为此,我创建了一个给客户数量的CTE,递归地提取客户的关系和关系的关系。

例如,假设我有以下数据集:

  • 客户1,帐户1
  • 客户2,帐户1
  • 客户2,帐户2
  • 客户3,帐户2
  • 客户4,帐户3

为客户编号1运行CTE我想要获取客户1,2,3和帐户1,2。但是,由于这是递归的,我还提取每个重复的关系(1 - > 2 - > 1)直到预设的最大深度。有什么方法我可以"标记"现有的关系,所以它不会被反复选中?

这是我的CTE,基于微软的CTE示例:

WITH EntityRelations(CUSTOMERNUMBER, ACCOUNTID, RELATEDWITH, Level)
AS
(
    SELECT 
        C.CUSTOMERNUMBER, 
        A.ACCOUNTNUMBER, 
        CREL.CUSTOMER related, 
        0 as level
    FROM CUSTOMER_ACCOUNT CA
    INNER JOIN CUSTOMER C
        ON C.ID = CA.CUSTOMERID
    INNER JOIN ACCOUNT A
        ON A.ID = CA.ACCOUNTID
    --Get direct relationships
    LEFT JOIN CUSTOMER_ACCOUNT CREL
        ON CREL.ACCOUNTID = CA.ACCOUNTID
        AND CREL.CUSTOMERID <> CA.CUSTOMERID
    WHERE BCE.CUSTOMER = 1

    UNION ALL
    --Recursion
    SELECT 
        C.CUSTOMERNUMBER, 
        A.ID, 
        CREL.CUSTOMER related, 
        Level+1
    FROM CUSTOMER_ACCOUNT CA
    INNER JOIN CUSTOMER C
        ON C.ID = CA.CUSTOMERID
    INNER JOIN ACCOUNT A
        ON A.ID = CA.ACCOUNTID
    --Get direct relationships
    LEFT JOIN CUSTOMER_ACCOUNT CREL
        ON CREL.ACCOUNTID = CA.ACCOUNTID
        AND CREL.CUSTOMERID <> CA.CUSTOMERID
    INNER JOIN EntityRelations ER
        ON ER.RELATEDWITH = CA.CUSTOMERID
    WHERE Level < 3 --Maximum
)

SELECT * FROM EntityRelations 

1 个答案:

答案 0 :(得分:0)

SELECT保留客户的csv列表,然后检查新客户是否在列表中。

带有想法的基本伪代码

 SELECT .... , ',' as lstCustomer   -- empty list

 UNION ALL

 SELECT .... ,  customerID || ',' as lstCustomer -- add new customer

 WHERE ',' || lstCustomer || ',' 
       NOT LIKE '%,' || customerID  || ',%'  
                         -- Check if list already have this customer

编辑:我假设您对CUSTOMER的展示次数有所需的限制,如果您希望限制为Customer, Account,则可以执行此类操作

 UNION ALL

 SELECT .... ,  '{' || customerID || '-' || accountID || '},' as lstCustomer 
                -- add new customer

 WHERE ',' || lstCustomer || ',' 
       NOT LIKE '%,{' || customerID  || '-' || accountID || '},%'  
                         -- Check if list already have this customer