我有一个名为FirstName
的列,但它包含first name
和middle initial
。
我试图比较的另一个表只有first name
。如何将两个表与包含中间初始值的一个表匹配?
例如,table A
David
为first name
,table B
为David L
。我匹配的不仅仅是名字,但我希望比较tablea.firstname
= tableb.firstname
,而不是在名字(空格)中间首字母后面。
答案 0 :(得分:1)
尽管我很欣赏社区在改进帖子方面的帮助,但不要改变段落的要点/症结。信息丢失是错失的机会。
提出问题,例如' 您是否拥有唯一标识名称的Surrogate个键?'或' 您的第一个表格是否包含结尾空格或前导空格?'如果命名标准一致,那么您的解决方案可以优雅而简单。否则,您可能需要在比较表格之前清理数据优先。
LIKE
运算符与通配符一起使用。Col_1 LIKE 'Name%'
)。此外,如果可能,请避免在谓词的两边使用函数(ON
,WHERE
,HAVING
),因为SQL可能无法正确使用列上的索引并执行代价高昂的操作表/索引扫描。解决方案A使用表格中的唯一ID:
SELECT CustomerID, [First Name] AS First_Name
FROM TableA
INNER JOIN TableB ON CustomerID = BuyerID
WHERE TableA.First_Name = SUBSTRING(TableB.firstname, 1, LEN(TableA.First_Name) )
容易,不是吗?这在WHERE子句中使用SARG,只比较重要的代码长度。
A. 然后在表格上运行DISTINCT
子句。 DISTINCT
基本上是GROUP BY
,并且消除了M:M
次比较。此外,您的代码仍然很精简,仍然可以正确,清晰地使用索引。
WITH C AS (SELECT FirstName FROM TableA)
SELECT B.FirstName
FROM C
RIGHT OUTER JOIN (SELECT DISTINCT First_Name FROM TableB) B ON C.FirstName = SUBSTRING(B.First_Name, 1, LEN(C.FirstName) )
WHERE TableA.[Tie_Breaker] = TableB.[Tie_Breaker]
请注意,RIGHT OUTER JOIN
为您提供了NULLS
,表示右表中没有匹配的行(TABLEB)。我把它留在这里,因为您可能希望比较表之间的匹配和不匹配(质量保证)。此外,您还可以利用ISNULL
或COALESCE
这样的简单功能,并为您在部门中拥有最精简的代码感到自豪。 :)
特别感谢@Matt通过WHERE子句指出了对断路器的需求
来源:MSDN,(n.d。)Predicates(Transact_SQL)。取自MSDN
答案 1 :(得分:0)
好的,这个话题似乎开始在兔子洞中走下坡路,因为在任何较大尺寸的数据集中,根据名字进行匹配绝不是一个简单的答案。这就是为什么有一个完整的行业建立在它上面。有一些数据清理产品可以帮助完成这样的任务,我已经使用但不代表。开发人员版和其他一些版本中提供的Microsoft工具是Data Quality Services https://msdn.microsoft.com/en-us/library/ff877925.aspx这将使用多个字符串匹配算法和多个字段来确定数据集中的重复项,这有点麻烦。 SSIS提供了一个模糊匹配任务,它也使用匹配算法......您可以构建自己的解决方案等。所有这些技术的一般共识是匹配除名称之外的数据。如电子邮件,地址,出生日期。
我在您的特定情况下的建议是确定数据集的清洁度,并尝试在这些答案中使用一些字符串操作技术,看看是什么让您最接近目标。如果其他信息也能够与两个数据库中的人员相关,我建议包括用于匹配目的的其他字段,这很可能是超过1种技术的组合或多次通过。[/ p >
我的建议是快速的字符串操作尝试。
只要它始终是名字空间首字母,您可以删除初始值并加入on语句中的值。同时反转字符串可以让你找到最后一个空格的位置,如果这个人有2个名字和一个名字。
DECLARE @FirstNameWithInitial VARCHAR(100) = 'bobby lee w'
DECLARE @FirstName VARCHAR(100) = 'bobby lee'
SELECT
--unknown number of characters after last space
LEFT(@FirstNameWithInitial,LEN(@FirstNameWithInitial) - CHARINDEX(' ',REVERSE(@FirstNameWithInitial)))
--always 2 characters
,LEFT(@FirstNameWithInitial, LEN(@FirstNameWithInitial) - 2)
,IIF(LEFT(@FirstNameWithInitial,LEN(@FirstNameWithInitial) - CHARINDEX(' ',REVERSE(@FirstNameWithInitial))) = @FirstName,'Join','No Match')
SELECT *
FROM
TableWithouInitial t
INNER JOIN TableWithInitial ti
ON t.Firstname = LEFT(ti.FirstNameWithInitial,LEN(ti.FirstNameWithInitial) - CHARINDEX(' ',REVERSE(ti.FirstNameWithInitial)))
添加将所有内容都放到第一个空间的方法,这样如果存在多于1的话,我就不会过度工程到达最后一个。
SELECT
LEFT(@FirstNameWithInitial,LEN(@FirstNameWithInitial) - CHARINDEX(' ',@FirstNameWithInitial))
是的,只需从上面的解决方案中删除REVERSE()
功能即可。个人偏好不使用SUBSTRING
或NULLIF
或ISNULL
。如果找不到匹配项,则CHARINDEX()
会返回0
,因此LEN - 0
将是字符串的整个长度,如果您不包含NULLIF
,则不会产生任何错误或ISNULL
。
答案 2 :(得分:0)
一个选项是连接名称列的子字符串,该子字符串仅包含名字:
SELECT t1.firstname
FROM tableA t1 INNER JOIN tableB t2
ON t1.firstname =
SUBSTRING(t2.firstname,
1,
CASE WHEN CHARINDEX(' ', t2.firstname) > 0
THEN CHARINDEX(' ', t2.firstname) - 1
ELSE LEN(t2.firstname)
END)
加入条件会将firstname
中的tableA
与tableB
中的第一个字进行比较,假设第一个单词是名字。
答案 3 :(得分:0)
Declare @Name Varchar(20) = 'David L'
SELECT LEFT(@Name , ISNULL(NULLIF(CHARINDEX(' ' , @name), 0), LEN(@Name)))
如果字符串中有空格,则上面的选择只会返回空格左侧的任何内容,您可以使用相同的逻辑来比较存储在不同表格的两个不同列中的名称
tablea.firstname = LEFT(tableb.firstname
, ISNULL(NULLIF(CHARINDEX(' ' , tableb.firstname), 0)
, LEN(tableb.firstname)))
答案 4 :(得分:0)
您可以在空格之前比较部分字段。简单的方法是这样的:
select t1.firstname,t2.firstname t2_name
from table1 t1
inner join table2 t2 on
--add space after the value to ensure the space exists
left(t1.firstname+' ',charindex(' ',t1.firstname,1)-1)
= left(t2.firstname+' ',charindex(' ',t2.firstname,1)-1)
答案 5 :(得分:0)
您可以使用charindex检查您的TableB.FirstName(John L)是否包含TableA.FirstName(John),希望这会有所帮助。
Where CHARINDEX('tablea.firstname','tableb.firstname')=1