关于字符串:在mysql中搜索电话号码

关于字符串:在mysql中搜索电话号码

Searching for phone numbers in mysql

我有一张桌子,上面满是任意格式的电话号码,例如

1
2
3
4
027 123 5644
021 393-5593
(07) 123 456
042123456

我需要搜索类似任意格式的电话号码(例如07123456应该找到条目(07) 123 456

我将以普通的编程语言执行此操作的方法是将所有非数字字符从"针"中去除,然后遍历大海捞针中的每个数字,将所有非数字字符从中去除,然后与针进行比较,例如(ruby)

1
2
3
4
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"方法。感谢您的所有反馈!


could you use a"replace" function to strip out any instances of"(","-" and"",

我不担心结果是数字。
我需要考虑的主要字符是+-()space
那么该解决方案看起来像这样吗?

1
2
3
4
SELECT * FROM people
WHERE
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(phonenumber, '('),')'),'-'),' '),'+')
LIKE '123456'

那不是很慢吗?


这从一开始就是一个问题。您进行的任何类型的搜索都需要进行表扫描,我们都知道这很不好。

在除去所有格式字符后,如何添加带有当前电话号码哈希的列。然后,您至少可以为哈希值建立索引,并避免进行完整的表扫描。

还是数据量很小并且预计增长不会很大?
然后也许只是将所有数字吸入客户端并在其中进行搜索。


我知道这是古老的历史,但是我在寻找类似解决方案时发现了它。

一个简单的REGEXP可能起作用:

1
select * from phone_table where phone1 REGEXP"07[^0-9]*123[^0-9]*456"

这将与phonenumber列匹配,带有或不带有任何分隔字符。


这是MySQL的问题-regex函数可以匹配,但不能替换。请参阅此帖子以获取可能的解决方案。


一个开箱即用的想法,但是您是否可以使用"替换"功能删除"(","-"和""的任何实例,然后使用" isnumeric"功能测试是否结果字符串是数字吗?

然后,您可以对要搜索的电话号码字符串执行相同的操作,并将它们比较为整数。

当然,这不适用于1800-MATT-ROCKS之类的数字。 :)


我的解决方案将类似于约翰·代尔(John Dyer)所说的。我要添加第二列(例如phoneStripped),该列会在插入和更新时被剥离。为该列建立索引并对其进行搜索(当然,在删除搜索词之后)。

您也可以添加触发器以自动更新列,尽管我没有使用触发器。但是就像您说的那样,编写MySQL代码来剥离字符串确实很困难,因此仅在客户端代码中执行操作可能会更容易。

(我知道这很晚了,但是我才开始四处看看:)


我建议使用php函数,而不要使用mysql模式,因此您将具有以下代码:

1
2
3
4
5
6
$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 ."'";

请参阅

http://www.mfs-erp.org/community/blog/find-phone-number-in-database-format-independent

因为只有mysql能"看到"它,所以正则表达式在视觉上不会令人吃惊。请注意,您应在正则表达式中使用" *",而不是""(在OP中以[\\\\ D]开头)。

一些用户担心性能(非索引搜索),但是在有100000个客户的表中,从用户界面发出此查询后,立即返回,没有明显的延迟。


是否可以运行查询以重新格式化数据以匹配所需格式,然后仅运行简单查询?这样,即使最初的重新格式化很慢,您也没关系。


可能的解决方案可以在以下网址找到://udf-regexp.php-baustelle.de/trac/

需要安装其他软件包,然后可以使用REGEXP_REPLACE


正如John Dyer所说,您应该考虑将数据固定在数据库中,并且仅存储数字。但是,如果您面临与我相同的情况(我无法运行更新查询),则发现的解决方法是合并两个查询。

"内部"查询将检索所有电话号码,并将其格式化以除去非数字字符。

1
SELECT REGEXP_REPLACE(column_name, '[^0-9]', '') phone_formatted FROM table_name

其结果将是所有没有任何特殊字符的电话号码。之后,"外部"查询仅需要获取您要查找的条目。
这两个查询将是:

1
2
3
SELECT phone_formatted FROM (
    SELECT REGEXP_REPLACE(column_name, '[^0-9]', '') phone_formatted FROM table_name
) AS result WHERE phone_formatted = 9999999999

重要提示:不使用AS结果,但应该在该位置以避免错误。


创建用户定义的函数以动态创建正则表达式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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 ;

在存储过程中调用该用户定义函数。

1
2
3
DECLARE var_PhoneNumberRegex        VARCHAR(200);
SET var_PhoneNumberRegex = udfn_GetPhoneRegex('+ 123 555 7890');
SELECT * FROM Customer WHERE phonenumber REGEXP var_PhoneNumberRegex;

我是祸。我最终这样做:

1
2
3
mre = mobile_number && ('%' + mobile_number.gsub(/\\D/, '').scan(/./m).join('%'))

find(:first, :conditions => ['trim(mobile_phone) like ?', mre])

这只是一个主意,但是您不能使用Regex快速删除字符,然后与@Matt Hamilton建议的字符进行比较吗?

甚至可以设置一个视图(不确定视图中是否使用mysql),该视图会将正则表达式剥离的所有电话号码都保留为普通电话号码?


MySQL can search based on regular expressions.

当然可以,但是考虑到任意格式,如果我的干草堆包含"(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)

如果是这种情况,那与我的%%%%%想法差不多吗?


我将使用Google的libPhoneNumber将数字格式化为E164格式。我将添加第二列" e164_number"来存储e164格式的数字并在其上添加索引。


如果这是定期发生的事情,则可能将数据修改为全部一种格式,然后设置搜索表单以去除任何非字母数字(如果允许使用310-BELL这样的数字),一个好主意。以易于搜索的格式存储数据是成功的一半。


推荐阅读

    linux命令搜索大全?

    linux命令搜索大全?,地址,工作,系统,命令,管理,目录,标准,基础,工具,网络,lin

    linux搜索过去命令?

    linux搜索过去命令?,系统,信息,命令,名称,工作,预期,数字,地址,标准,服务,Lin

    linux命令搜索命令?

    linux命令搜索命令?,系统,位置,地址,标准,管理,信息,命令,名称,工作,文件,Lin

    linux命令查找字符串?

    linux命令查找字符串?,工具,信息,命令,字符串,系统,工作,文件,范本,样式,文

    linux日志搜索命令?

    linux日志搜索命令?,信息,系统,对比,工具,一致,日志,文件,命令,实时,网络,lin

    linux命令字符搜索?

    linux命令字符搜索?,系统,工具,命令,灵活,信息,工作,字符串,文本,文件,模式,l

    linux搜索筛选命令?

    linux搜索筛选命令?,系统,数字,电脑,盘后,盘中,工具,信息,文件,命令,字符,在l

    linux搜索日志的命令?

    linux搜索日志的命令?,实时,信息,系统,对比,最新,情况,日志,命令,地方,数据,

    linux全局搜索命令?

    linux全局搜索命令?,系统,工具,命令,灵活,信息,工作,字符串,文件,全局,字符,L

    linux命令搜索值高亮?

    linux命令搜索值高亮?,包装,网上,环境,命令,颜色,文件,语法,终端,界面,方法,l

    linux搜索命令大全?

    linux搜索命令大全?,工作,地址,系统,命令,目录,灵活,工具,管理,信息,基础,lin

    linux搜索日志命令?

    linux搜索日志命令?,实时,信息,对比,情况,日志,命令,生产,环境,系统,指令,lin

    linux命令搜索文件名?

    linux命令搜索文件名?,系统,工具,信息,名称,命令,文件,标准,字符串,文件名,

    linux命令模式搜索?

    linux命令模式搜索?,系统,地址,工作,信息,命令,位置,管理,文件,目录,内容,lin

    linux命令字符串匹配?

    linux命令字符串匹配?,系统,工具,命令,字符串,灵活,状态,文件,文本,模式,管

    兄弟连linux搜索命令?

    兄弟连linux搜索命令?,系统,工作,名称,命令,信息,文件,工具,目录,字符串,文

    python字符串截取?

    python字符串截取?,代码,步长,位置,分析,字符串,字符,信息,灵活,数字,表示,在

    Python编程语言特征

    Python编程语言特征,代码,异常,环境,管理,培训,标准,检测,网络,特征,模块,1