我有一个客户表,我们将电话号码字段定义为varchar(50)。由于没有验证,不同的客户以他们自己喜欢的方式保存了电话号码,例如
cust1 - > XXX-XXX-XXX
cust2 - > (XXX)XXX-XXX
cust3 - > xxx xxx xxx
到目前为止,这还没有造成任何问题,因为没有人使用电话号码进行搜索。 添加搜索功能后,客户端无法获得所需的结果,因为要匹配您还必须以相同的格式提供查询。我是否有办法只考虑数字来搜索电话栏?
答案 0 :(得分:2)
我的答案与Andy Korneyev的答案非常相似,但我要补充一些额外的细节。
如果表格中有很多行,建议使用标准化格式的列,这样,当您的用户想要查找电话号码时,应用程序会对其进行规范化并查找它
如果您通过规范化用户条目以及表格列中的值来使用任何解决方案进行查询,则服务器必须执行额外的工作,并且无法使用索引。
因此,到目前为止,最好的解决方案是使用标准化列。
可以直接从应用程序创建此列,或将触发器应用于原始表以创建规范化列(我个人不会使用触发器)。
最后,在寻找电话号码时有一个典型的例子:有时候人们会包含前缀,有时则不包括。所以你必须使用像WHERE T.PhoneNumber LIKE '%5551234'
这样的谓词。如果您这样做,如果您的电话号码列已编入索引,则无法获得任何好处。
为了解决这个典型的问题,数字被存储归一化和反转,即前一个样本将被存储如下:' 4321555'或者' 4312555070',例如,如果有的话是一个前缀。
当您的用户查找“5551234”时,将其标准化(即非数字的移动)甚至对于' 0705551234',应用程序可以反转它,并使用这样的谓词:
WHERE T.PhoneNumber LIKE '4321555%' OR '4321555' LIKE T.PhoneNumber+'%'
第一部分介绍了DB中的数字有前缀,用户没有指定的情况。 (即存储的电话号码为4321555070
)
第二部分涵盖了相反的情况。您可以通过此示例更清楚地看到它(当存储的电话号码为4321555
时):
WHERE T.PhoneNumber LIKE '4321555070%' OR '4321555070' LIKE T.PhoneNumber+'%'
那'为什么,在许多CRM中你会找到一个" ReversedPhoneNumber"字段。
顺便说一下,当你反转这个数字时,如果有一个可用的索引,它将会被使用,从而加速搜索。
答案 1 :(得分:0)
直截了当的解决方案:
after insert, update
触发器,它将填充旧列中的新列。现在你可以删除所有" nondigits"从搜索查询中,只需使用新列进行搜索。
或者,如果您的数据库非常小 - 您可以删除所有"非数字"在你的查询"在飞行中" - 但在这种情况下,即使您的电话栏上有索引,也不会使用索引。
答案 2 :(得分:0)
SELECT customer, phonenum
FROM table
WHERE replace(replace(replace(replace(phonenum,'-',''),'(',''),')',''),' ','') like '%1234%'
将like '%1234%'
替换为您用于定义搜索的参数
答案 3 :(得分:0)
使用以下功能从电话号码中提取 INT 值:
CREATE FUNCTION ExtractInteger(@String VARCHAR(2000))
RETURNS VARCHAR(1000)
AS
BEGIN
DECLARE @Count INT
DECLARE @IntNumbers VARCHAR(1000)
SET @Count = 0
SET @IntNumbers = ''
WHILE @Count <= LEN(@String)
BEGIN
IF SUBSTRING(@String,@Count,1) >= '0'
AND SUBSTRING(@String,@Count,1) <= '9'
BEGIN
SET @IntNumbers = @IntNumbers + SUBSTRING(@String,@Count,1)
END
SET @Count = @Count + 1
END
RETURN @IntNumbers
END
搜索 电话号码,如下所示:('323-111'='(323)111')
DECLARE @SearchNumber VARCHAR(1000)
SET @SearchNumber = '323-111'
SELECT 'MatchFount' AS RESULT
WHERE dbo.ExtractInteger(@SearchNumber)
LIKE '%'+ dbo.ExtractInteger('(323)111')+'%'