比较SQL Server中以下字符串集的最佳方法是什么?
目的:此存储过程的主要目的是将一组客户输入名称与特定帐户的客户数据库中存在的名称进行比较。如果输入名称与数据库中的名称存在差异,则应触发使用新名称信息更新客户数据库。
输入格式:FirstName [MiddleName] LastName
数据库中的值格式:LastName, FirstName MiddleName
当出现这样的名字时会出现并发症,
输入:Dr. John A. Mc Donald
数据库:Mc Donald, Dr. John A.
对于由2个或更多部分组成的姓氏,必须采用什么逻辑 确保将输入中的姓氏与数据库中的姓氏进行比较,同样确保名字和中间名。
我已经考虑过将数据库值分解为临时HASH表,因为我知道数据库中','之前的所有内容都是姓。然后,我可以检查输入是否包含姓氏,并从中分出FirstName [MiddleName]
,以便对数据库执行与','之后的值的另一次比较。
然而,还有第二部分。如果输入名称具有完全新的姓氏(即,如果数据库中的名称是Mary Smith,但更新的输入名称现在是Mary Mc Donald)。在这种情况下,将','之前的姓氏的数据库值与输入名称进行比较将导致不匹配,这是正确的,但此时代码如何知道姓氏在输入值中的起始位置?怎么知道她的中间名不是MC而她的姓唐纳德?
有没有人不得不像以前那样处理类似的问题?你最终选择了哪些解决方案?
我非常感谢您的意见和建议。
谢谢。
答案 0 :(得分:2)
实际上,知道像“Mary Jane Evelyn Scott”这样的名字是第一个中间的最后一个 - 最后一个2,第一个 - 第一个 - 中间 - 最后一个,第一个 - 第一个 - 最后一个 - 最后一个,这在计算上是非常困难的(如果不是不可能的话) ,或者其他一些组合......而且甚至没有进入文化考虑......
所以个人而言,我建议改变数据结构(相应地,应用程序的输入字段)。而不是名称的单个字符串,将其分成几个字段,例如:
FullName{
title, //i.e. Dr., Professor, etc.
firstName, //or given name
middleName, //doesn't exist in all countries!
lastName, //or surname
qualifiers //i.e. Sr., Jr., fils, D.D.S., PE, Ph.D., etc.
}
然后用户可以选择他们的名字是“Mary”,他们的中间名是“Jane Evelyn”,他们的姓氏是“Scott”。
<强>更新强>
根据您的意见,如果您必须完全在SQL中执行此操作,我将执行以下操作:
因此,第1步将采用字符串“Dr. John A. Mc Donald”并创建值表:
'Donald, Dr. John A. Mc'
'Mc Donald, Dr. John A.'
'A. Mc Donald, Dr. John'
'John A. Mc Donald, Dr.'
然后步骤2.将搜索数据库中所有这些字符串的出现次数。
假设MSSQL 2005或更高版本,步骤1.可以使用一些递归CTE来实现,并修改我用来拆分CSV字符串的方法(找到here)(SQL不是理想的语言对于这种形式的字符串操作......):
declare @str varchar(200)
set @str = 'Dr. John A. Mc Donald'
--Create a numbers table
select [Number] = identity(int)
into #Numbers
from sysobjects s1
cross join sysobjects s2
create unique clustered index Number_ind on #Numbers(Number) with IGNORE_DUP_KEY
;with nameParts as (
--Split the name string at the spaces.
select [ord] = row_number() over(order by Number),
[part] = substring(fn1, Number, charindex(' ', fn1+' ', Number) - Number)
from (select @str fn1) s
join #Numbers n on substring(' '+fn1, Number, 1) = ' '
where Number<=Len(fn1)+1
),
lastNames as (
--Build all possible lastName strings.
select [firstOrd]=ord, [lastOrd]=ord, [lastName]=cast(part as varchar(max))
from nameParts
where ord!=1 --remove the case where the whole string is the last name
UNION ALL
select firstOrd, p.ord, l.lastName+' '+p.part
from lastNames l
join nameParts p on l.lastOrd+1=p.ord
),
firstNames as (
--Build all possible firstName strings.
select [firstOrd]=ord, [lastOrd]=ord, [firstName]=cast(part as varchar(max))
from nameParts
where ord!=(select max(ord) from nameParts) --remove the case where the whole string is the first name
UNION ALL
select p.ord, f.lastOrd, p.part+' '+f.firstName
from firstNames f
join nameParts p on f.firstOrd-1 = p.ord
)
--Combine for all possible name strings.
select ln.lastName+', '+fn.firstName
from firstNames fn
join lastNames ln on fn.lastOrd+1=ln.firstOrd
where fn.firstOrd=1
and ln.lastOrd = (select max(ord) from nameParts)
drop table #Numbers
答案 1 :(得分:1)
由于我对来自第三方的数据有着可怕的经验,因此几乎可以保证输入数据将包含大量不符合指定格式的垃圾。
当您尝试匹配数据多部分字符串数据时,我会使用以下方法将输入和数据预处理为“规范化字符串”。
使用样本数据,此函数将产生:
博士。 John A. Mc Donald - &gt; a-donald-dr-john-mc
麦克唐纳德博士 John A .-&gt;一个-唐纳德-DR约翰-MC
不幸的是,它不是100%防弹,有些情况下退化的输入会产生无效的匹配。
答案 2 :(得分:0)
您的姓名字段在数据库中不好。重新设计并摆脱它。如果您有名字,中间名,姓氏,前缀和后缀结构,则可以使用具有您正在使用的结构的hava计算字段。但这是一种非常差的存储数据的方式,您的首要任务应该是停止使用它。
既然你有一个共同的客户ID,为什么你不匹配而不是名字?