Поиск телефонных номеров в MySQL - PullRequest
11 голосов
/ 03 сентября 2008

У меня есть таблица, заполненная произвольно отформатированными телефонными номерами, например,

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'

Разве это не было бы ужасно медленно?

Ответы [ 15 ]

11 голосов
/ 03 сентября 2008

Это похоже на проблему с самого начала. Любой ваш поиск потребует сканирования таблицы, и мы все знаем, что это плохо.

Как насчет добавления столбца с хэшем текущих телефонных номеров после удаления всех символов форматирования. Тогда вы можете хотя бы проиндексировать значения хешей и избежать полного сканирования таблицы.

Или объем данных невелик и не ожидается значительного увеличения? Тогда, может быть, просто засунув все цифры в клиент и выполнив поиск там.

4 голосов
/ 23 января 2014

Я знаю, что это древняя история, но я нашел ее, когда искал похожее решение.

Может работать простой REGEXP:

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

Это будет соответствовать столбцу phonenumber с разделительными знаками или без них.

2 голосов
/ 03 января 2011

Я предлагаю использовать функции 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 . "' ";
2 голосов
/ 18 сентября 2008

Моим решением было бы что-то вроде того, что сказал Джон Дайер. Я бы добавил второй столбец (например, phoneStripped), который удаляется при вставке и обновлении. Индексируйте этот столбец и выполняйте поиск по нему (разумеется, после удаления вашего поискового запроса).

Вы также можете добавить триггер для автоматического обновления столбца, хотя я не работал с триггерами. Но, как вы сказали, действительно трудно написать код MySQL для удаления строк, поэтому, вероятно, проще просто сделать это в своем клиентском коде.

(Я знаю, что уже поздно, но я только начал осматриваться здесь:)

2 голосов
/ 03 сентября 2008

Это проблема с MySQL - функция регулярного выражения может соответствовать, но не может заменить. См. Этот пост для возможного решения.

2 голосов
/ 03 сентября 2008

Идея «из коробки», но не могли бы вы использовать функцию «заменить» для удаления любых экземпляров «(», «-» и «», а затем использовать функцию «isnumeric» для проверки результирующая строка является числом?

Тогда вы можете сделать то же самое с искомой строкой телефонного номера и сравнить их как целые числа.

Конечно, это не будет работать для чисел типа 1800-MATT-ROCKS. :)

1 голос
/ 11 марта 2010

См

http://www.mfs -erp.org / сообщество / блог / найти-телефон-номер-в-базы данных формата независимого

На самом деле проблема не в том, что регулярное выражение стало бы ужасно визуально, поскольку только mysql «видит» его. Обратите внимание, что вместо '+' (ср. Пост с [\ D] из OP) вы должны использовать '*' в регулярном выражении.

Некоторые пользователи обеспокоены производительностью (неиндексируемый поиск), но в таблице с 100000 клиентов этот запрос при выдаче из пользовательского интерфейса немедленно возвращается без заметной задержки.

1 голос
/ 03 сентября 2008

Можно ли выполнить запрос для переформатирования данных в соответствии с желаемым форматом, а затем просто выполнить простой запрос? Таким образом, даже если первоначальное переформатирование идет медленно, это не имеет значения.

0 голосов
/ 30 января 2017

Я бы использовал Google libPhoneNumber для форматирования числа в формат E164. Я хотел бы добавить второй столбец с именем «e164_number» для хранения отформатированного числа e164 и добавить индекс для него.

0 голосов
/ 18 сентября 2013

Создайте пользовательскую функцию для динамического создания 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;
...