在mysql中搜索电话号码

时间:2008-09-02 23:01:32

标签: mysql string search phone-number

我有一张桌子,里面装满了任意格式的电话号码,比如这个

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'解决方案'

  • CONCATSUBSTR
  • 的法兰克福查询混为一谈
  • 在针的每个字符之间插入一个%(所以就像这样:%0%7%1%2%3%4%5%6%

但是,这些都不是特别优雅的解决方案 希望有人可以提供帮助,或者我可能被迫使用%%%%%%解决方案

更新:这是在相对固定的数据集上运行,可能有几百行。我只是不想做一些非常糟糕的事情,未来的程序员会哭泣。

如果数据集增长,我将采用'phoneStripped'方法。感谢您的所有反馈!


  

你可以使用“替换”功能去掉任何“(”,“ - ”和“”,

的实例

我并不担心结果是数字的。 我需要考虑的主要字符是+-()space 那个解决方案会是这样吗?

SELECT * FROM people 
WHERE 
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(phonenumber, '('),')'),'-'),' '),'+')
LIKE '123456'

这不是非常慢吗?

16 个答案:

答案 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结果,但应该在该位置以免出错。