我有一张桌子,里面装满了任意格式的电话号码,比如这个
027 123 5644
021 393-5593
(07) 123 456
042123456
我需要以类似的任意格式搜索电话号码(例如07123456
应找到条目(07) 123 456
我用普通编程语言执行此操作的方法是将所有非数字字符从“针”中删除,然后遍历大海捞针中的每个数字,从中删除所有非数字字符,然后比较针,例如(在红宝石中)
digits_only = lambda{ |n| n.gsub /[^\d]/, '' }
needle = digits_only[input_phone_number]
haystack.map(&digits_only).include?(needle)
问题是,我需要在MySQL中执行此操作。它有许多字符串函数,其中没有一个看起来像我想要的那样。
目前我可以想到2'解决方案'
CONCAT
和SUBSTR
%
(所以就像这样:%0%7%1%2%3%4%5%6%
)但是,这些都不是特别优雅的解决方案 希望有人可以提供帮助,或者我可能被迫使用%%%%%%解决方案
如果数据集增长,我将采用'phoneStripped'方法。感谢您的所有反馈!
你可以使用“替换”功能去掉任何“(”,“ - ”和“”,
的实例
我并不担心结果是数字的。
我需要考虑的主要字符是+
,-
,(
,)
和space
那个解决方案会是这样吗?
SELECT * FROM people
WHERE
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(phonenumber, '('),')'),'-'),' '),'+')
LIKE '123456'
这不是非常慢吗?
答案 0 :(得分:11)
这从一开始就看起来像个问题。你做的任何类型的搜索都需要进行表扫描,我们都知道这很糟糕。
如何在删除所有格式化字符后添加包含当前电话号码哈希的列。然后,您至少可以索引哈希值并避免完整的表扫描。
或者数据量是否小而且预计不会增长太多? 然后可能只是将所有数字吸入客户端并在那里运行搜索。
答案 1 :(得分:4)
我知道这是古老的历史,但我在寻找类似的解决方案时找到了它。
简单的REGEXP可能有效:
select * from phone_table where phone1 REGEXP "07[^0-9]*123[^0-9]*456"
这将匹配phonenumber
列,有或没有任何分隔符。
答案 2 :(得分:2)
一个开箱即用的想法,但你可以使用“替换”功能去除任何“(”,“ - ”和“”的实例,然后使用“isnumeric”函数来测试是否结果字符串是一个数字?
然后你可以对你正在搜索的电话号码字符串做同样的事情,并将它们作为整数进行比较。
当然,这对像1800-MATT-ROCKS这样的数字不起作用。 :)
答案 3 :(得分:2)
这是MySQL的问题 - 正则表达式函数可以匹配,但它无法替代。 See this post寻求可能的解决方案。
答案 4 :(得分:2)
我的解决方案将与John Dyer所说的一致。我会添加第二列(例如phoneStripped),它会在插入和更新时被剥离。索引此列并在其上进行搜索(当然,在剥离搜索词后)。
您还可以添加触发器来自动更新列,但我没有使用触发器。但是就像你说的那样,编写用于去除字符串的MySQL代码真的很困难,所以在客户端代码中执行它可能更容易。
(我知道这已经很晚了,但我刚开始环顾四周:)
答案 5 :(得分:2)
我建议使用php函数,而不是mysql模式,所以你会有这样的代码:
$tmp_phone = '';
for ($i=0; $i < strlen($phone); $i++)
if (is_numeric($phone[$i]))
$tmp_phone .= '%'.$phone[$i];
$tmp_phone .= '%';
$search_condition .= " and phone LIKE '" . $tmp_phone . "' ";
答案 6 :(得分:1)
是否可以运行查询来重新格式化数据以匹配所需的格式,然后只运行一个简单的查询?这样,即使最初的重新格式化很慢,你也无所谓。
答案 7 :(得分:1)
见
http://www.mfs-erp.org/community/blog/find-phone-number-in-database-format-independent
正则表达式在视觉上令人震惊并不是真正的问题,因为只有mysql“看到”它。请注意,您应该在正则表达式中使用'*'而不是'+'(带有[\ D]来自OP的文件)。
有些用户关注性能(非索引搜索),但在具有100000个客户的表中,此查询从用户界面发出时立即返回,没有明显的延迟。
答案 8 :(得分:0)
MySQL可以基于正则表达式进行搜索。
当然,但是考虑到任意格式,如果我的草垛包含"(027) 123 456"
(请记住空格的位置可以改变,它可以很容易027 12 3456
,我想将它与{027123456
匹配1}},我的正则表达式是否需要成为这个?
"^[\D]+0[\D]+2[\D]+7[\D]+1[\D]+2[\D]+3[\D]+4[\D]+5[\D]+6$"
(实际上情况会更糟,因为mysql手册似乎并不表示它支持\D
)
如果是这种情况,是不是与我的%%%%%想法大致相同?
答案 9 :(得分:0)
只是一个想法,但你不能用正则表达式快速删除角色,然后比较像@Matt Hamilton建议的吗?
甚至可能设置一个视图(不确定视图上的mysql)会将正则表达式剥离的所有电话号码保存为普通电话号码吗?
答案 10 :(得分:0)
我有祸了。我最终这样做了:
mre = mobile_number && ('%' + mobile_number.gsub(/\D/, '').scan(/./m).join('%'))
find(:first, :conditions => ['trim(mobile_phone) like ?', mre])
答案 11 :(得分:0)
如果这是定期发生的事情,可能会将数据修改为所有格式,然后设置搜索表单以删除任何非字母数字(如果您允许310-BELL之类的数字)将是一个好主意。以易于搜索的格式获取数据只是成功的一半。
答案 12 :(得分:0)
可以在http://udf-regexp.php-baustelle.de/trac /
找到可能的解决方案。需要安装额外的软件包,然后您可以使用REGEXP_REPLACE
答案 13 :(得分:0)
创建用户定义的函数以动态创建Regex。
DELIMITER //
CREATE FUNCTION udfn_GetPhoneRegex
(
var_Input VARCHAR(25)
)
RETURNS VARCHAR(200)
BEGIN
DECLARE iterator INT DEFAULT 1;
DECLARE phoneregex VARCHAR(200) DEFAULT '';
DECLARE output VARCHAR(25) DEFAULT '';
WHILE iterator < (LENGTH(var_Input) + 1) DO
IF SUBSTRING(var_Input, iterator, 1) IN ( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ) THEN
SET output = CONCAT(output, SUBSTRING(var_Input, iterator, 1));
END IF;
SET iterator = iterator + 1;
END WHILE;
SET output = RIGHT(output,10);
SET iterator = 1;
WHILE iterator < (LENGTH(output) + 1) DO
SET phoneregex = CONCAT(phoneregex,'[^0-9]*',SUBSTRING(output, iterator, 1));
SET iterator = iterator + 1;
END WHILE;
SET phoneregex = CONCAT(phoneregex,'$');
RETURN phoneregex;
END//
DELIMITER ;
在存储过程中调用用户定义的函数。
DECLARE var_PhoneNumberRegex VARCHAR(200);
SET var_PhoneNumberRegex = udfn_GetPhoneRegex('+ 123 555 7890');
SELECT * FROM Customer WHERE phonenumber REGEXP var_PhoneNumberRegex;
答案 14 :(得分:0)
我会使用Google libPhoneNumber将数字格式化为E164格式。我会添加第二列名为&#34; e164_number&#34;存储e164格式的数字并在其上添加索引。
答案 15 :(得分:0)
正如John Dyer所说,您应该考虑将数据固定在数据库中,并且只存储数字。但是,如果您遇到与我相同的情况(我无法运行更新查询),则发现的解决方法是合并两个查询。
“内部”查询将检索所有电话号码,并格式化它们以除去非数字字符。
SELECT REGEXP_REPLACE(column_name, '[^0-9]', '') phone_formatted FROM table_name
其结果将是所有没有任何特殊字符的电话号码。之后,“外部”查询仅需要获取您要查找的条目。 这两个查询将是:
SELECT phone_formatted FROM (
SELECT REGEXP_REPLACE(column_name, '[^0-9]', '') phone_formatted FROM table_name
) AS result WHERE phone_formatted = 9999999999
重要提示:未使用 AS结果,但应该在该位置以免出错。