sql - 查找链中的最后一条记录 - 客户合并流程
问题描述
我正在从另一个供应商的系统导入客户数据,我们有合并流程,用于识别潜在的重复客户账户,如果它们满足某些条件(例如相同的名字、姓氏、SSN 和 DOB),它们会合并它们。在这个过程中,我看到了我们在哪里创建链——例如,客户 A 被合并到客户 B,然后客户 B 被合并到客户 C。
我希望做的是识别这些链并更新客户记录以指向链中的最后一条记录。所以在我上面的例子中,客户 A 和客户 B 在他们合并的 To 字段中都有客户 C 的 id。
CustID FName LName CustStatusType isMerged MergedTo
1 Kevin Smith M 1 2
2 Kevin Smith M 1 3
3 Kevin Smith M 1 4
4 Kevin Smith O 0 NULL
5 Mary Jones O 0 NULL
6 Wyatt Earp M 1 7
7 Wyatt Earp O 1 NULL
8 Bruce Wayn M 1 10
9 Brice Wayne M 1 10
10 Bruce Wane M 1 11
11 Bruce Wayne O 1 NULL
CustStatusType 指示客户帐户是打开(“O”)还是合并(“M”)。然后我们有一个 isMerged 字段作为 BIT 字段,指示帐户是否已合并,最后是 MergedTo 字段,指示记录合并到哪个客户帐户。
通过提供的示例,我想要实现的是让 1 和 2 的 CustID 记录将其 MergedTo 记录设置为 3 - 而 CustID 3 可以更新或保持原样。对于客户 ID 4、5 和 6 - 可以找到这些记录,无需更新。但在客户 ID 8 - 10 上,我希望将这些记录设置为 11 - 如下表所示。
CustID FName LName CustStatusType isMerged MergedTo
1 Kevin Smith M 1 4
2 Kevin Smith M 1 4
3 Kevin Smith M 1 4
4 Kevin Smith O 0 NULL
5 Mary Jones O 0 NULL
6 Wyatt Earp M 1 7
7 Wyatt Earp O 1 NULL
8 Bruce Wayn M 1 11
9 Brice Wayne M 1 11
10 Bruce Wane M 1 11
11 Bruce Wayne O 1 NULL
我无法弄清楚如何使用 TSQL 来实现这一点 - 建议?
测试数据:
DROP TABLE IF EXISTS #Customers;
CREATE TABLE #Customers
(
CustomerID INT ,
FirstName VARCHAR (25) ,
LastName VARCHAR (25) ,
CustomerStatusTypeID VARCHAR (1) ,
isMerged BIT ,
MergedTo INT
);
INSERT INTO #Customers
VALUES ( 1, 'Kevin', 'Smith', 'M', 1, 2 ) ,
( 2, 'Kevin', 'Smith', 'M', 1, 3 ) ,
( 3, 'Kevin', 'Smith', 'M', 1, 4 ) ,
( 4, 'Kevin', 'Smith', 'O', 0, NULL ) ,
( 5, 'Mary', 'Jones', 'O', 0, NULL ) ,
( 6, 'Wyatt', 'Earp', 'M', 1, 7 ) ,
( 7, 'Wyatt', 'Earp', 'O', 1, NULL ) ,
( 8, 'Bruce', 'Wayn', 'M', 1, 10 ) ,
( 9, 'Brice', 'Wayne', 'M', 1, 10 ) ,
( 10, 'Bruce', 'Wane', 'M', 1, 11 ) ,
( 11, 'Bruce', 'Wayne', 'O', 1, NULL );
SELECT *
FROM #Customers;
DROP TABLE #Customers;
解决方案
对于你的例子soundex()
似乎足够好。它返回一个代码,该代码基于单词在英语中的发音。在名字和姓氏上使用它来连接客户表和查询客户表的子查询,添加row_number()
由名称的 Soundex 分区并按 ID 降序排列的顺序 - 将“最新”记录编号为 1。对于连接条件使用名称的 Soundex、行号 1,当然还有 ID 的不等式。
UPDATE c1
SET c1.mergedto = x.customerid
FROM #customers c1
LEFT JOIN (SELECT c2.customerid,
soundex(c2.firstname) sefn,
soundex(c2.lastname) seln,
row_number() OVER (PARTITION BY soundex(c2.firstname),
soundex(c2.lastname)
ORDER BY c2.customerid DESC) rn
FROM #customers c2) x
ON x.sefn = soundex(c1.firstname)
AND x.seln = soundex(c1.lastname)
AND x.rn = 1
AND x.customerid <> c1.customerid;
我真的不明白customerstatustypeid
andismerged
列背后的概念。据我了解,它们都源自是否mergedto
为空。但是样本数据既不是预期的结果也不支持这一点。但是由于这些列显然在您的示例输入和输出之间没有变化,我想没关系,我只是不理会它们。
如果 Soundex 证明不足以满足您的需求,您可能需要寻找其他字符串距离指标,例如Levenshtein distance。AFAIK 没有包含在 SQL Server 中的实现,但搜索引擎可能会吐出第三方的实现,或者可能有一些可以通过 CLR 使用的东西。或者你自己滚动,当然。
推荐阅读
- moodle - 如何浏览所有上传到 Moodle 的文件
- php - 如何处理 php artisan 路由?
- javascript - 脚本重定向到 URL 并刷新
- typescript - 打字稿:类型'{ id:字符串;} & 挑选
>' 不可分配给类型 'T' - javascript - 正则表达式测试空格分隔的字符
- php - 如何在php中用法语硬编码月份名称?
- c - 使用 Green Hills 编译器将静态库与头文件链接起来
- swift - Xcode 故事板类没有模块
- javascript - 函数、全局变量和局部变量
- scala - 将订阅 onError Scala.RX 放入 Observable 是否有害
?