【问题标题】:Using a Recursive CTE function to check every row against every other row使用递归 CTE 函数检查每一行与其他每一行
【发布时间】:2015-03-22 07:42:29
【问题描述】:

我正在尝试更新一个表,以便我标记任何具有重复名称条目的条目。我做了一些处理来删除一些常见的前缀和后缀,然后可以使用模糊匹配的 CLR 来运行两个名称。我把它写成一个嵌套游标,目前它需要大约 4 个小时来运行所有记录,因为我必须检查每一行与其他每一行。我读过使用递归 CTE 可以显着提高性能,但是我有点 SQL 菜鸟,不能让它工作。我想我需要将一个递归 CTE 嵌套到另一个中,但不确定如何。

目前我有类似的东西:

;WITH AllOrgs (CompanyId, CompanyRoleId, Name, Recognized, Level)
AS 
(
    SELECT C.CompanyId, C.CompanyRoleId, C.Name, C.Recognized, 1
    FROM Company O
    WHERE DuplicateOfCompanyId IS NULL
    UNION ALL
    SELECT C.CompanyId, C.CompanyRoleId, C.Name, R.Recognized, R.Level + 1
    FROM AllOrgs R INNER JOIN Company C
    ON C.CompanyId = R.CompanyId
), 
DuplicateOrgs (CompanyId, CompanyRoleId, Name, Recognized, Level)
As 
(
    SELECT * FROM AllOrgs
    WHERE Recognized = 0 -- Recognized is what the companies are marked when we are satisfied they aren't incorrect
)
UPDATE O
SET C.DuplicateOfCompanyId = A.CompanyId
FROM Company O JOIN DuplicateOrgs A
ON C.CompanyId = A.CompanyID
WHERE master.dbo.fnClrFuzzyMatch(dbo.fnCleanUpCompanyName(A.Name), dbo.fnCleanUpCompanyName(C.Name)) 
    > @CompanyNameMatchValueThreshold
AND A.CompanyRoleID = C.CompanyRoleId -- Role ID must match as duplicates who provide a different function are fine

但每当我尝试运行它时,我都会收到“语句终止。在语句完成之前,最大递归 100 已用尽。”所以我显然在做一些愚蠢的事情。

【问题讨论】:

  • 递归并不比游标好多少。如果您想将一行与具有相同 CompanyID 的任何其他行进行比较,请在 CompanyID 上执行自连接,条件是排除将一行连接到自身(例如 A.ID B.ID),然后将模糊匹配功能应用于结果
  • 对于该错误消息,您需要 OPTION (MAXRECURSION 0);如果您通过大量数据进行递归,这可能会使您的服务器崩溃
  • 你能展示数据示例吗?您确定完全不使用游标或递归查询就不能做同样的事情吗?
  • 作为一个快速数据示例,您有两行:ID|RoleID|Name|Recognized|IsduplicateOf 1|1|Quickimart|1|NULL 2|1|Quickimart Ltd|0|NULL 我想更新第二行作为第一行的副本,我希望能够对表中的每一行针对其他每一行执行此操作。

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


【解决方案1】:

您的递归不会终止,因为您总是将锚值本身插入一个新级别。公司中只有一行的示例:

锚点执行后的AllOrgs:
CompanyId1, CompanyRoleId1, name1, Recognized1, 1

递归 1 后的 AllOrgs:
CompanyId1、CompanyRoleId1、name1、Recognized1、1
CompanyId1, CompanyRoleId1, name1, Recognized1, 2

递归 2 后的 AllOrgs:
CompanyId1、CompanyRoleId1、name1、Recognized1、1
CompanyId1、CompanyRoleId1、name1、Recognized1、2
CompanyId1, CompanyRoleId1, name1, Recognized1, 3

...

尝试使用自联接:

UPDATE C 
SET DuplicateOfCompanyId = Dup.CompanyId
FROM Company C
JOIN Company Dup ON C.CompanyId <> Dup.CompanyID 
    AND master.dbo.fnClrFuzzyMatch(dbo.fnCleanUpCompanyName(C.Name), dbo.fnCleanUpCompanyName(Dup.Name)) > @CompanyNameMatchValueThreshold
    AND C.CompanyRoleID = Dup.CompanyRoleId

注意:如果公司有多个重复项,则 duplicateOfCompanyId 可能是任意的且不一致。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 2017-01-15
    • 1970-01-01
    • 1970-01-01
    • 2021-09-29
    • 2011-12-13
    相关资源
    最近更新 更多