Поиск номеров телефонов в mysql

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

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 решениях

  • Взломайте запрос franken CONCAT и SUBSTR
  • Вставьте % между каждым символом иглы (так вот так: %0%7%1%2%3%4%5%6%)

Однако ни одна из них не кажется особенно элегантными. Надеюсь, кто-то может помочь, или я могу быть вынужден использовать решение %%%%%%

Обновление: это работает с относительно фиксированным набором данных, возможно, несколько сотен строк. Я просто не хотел делать что-то смехотворное, что будущие программисты плакали.

Если набор данных будет расти, я возьму подход "phoneStripped". Спасибо за все отзывы!


Вы могли бы использовать функцию "replace", чтобы вырезать любые экземпляры "(", "-" и "",

Я не беспокоюсь о том, что результат является числовым. Основные символы, которые мне нужно рассмотреть, это +, -, (, ) и space Так будет ли это решение выглядеть так?

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

Не будет ли это ужасно медленным?

Ответ 1

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

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

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

Ответ 2

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

Простой REGEXP может работать:

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

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

Ответ 3

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

Затем вы можете сделать то же самое со строкой номера телефона, которую вы ищете, и сравнить их как целые числа.

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

Ответ 4

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

Ответ 5

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

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

(Я знаю, что это поздно, но я только начал искать здесь:)

Ответ 6

Я предлагаю использовать 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 . "' ";

Ответ 7

См

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

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

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

Ответ 8

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

Ответ 9

MySQL может выполнять поиск на основе регулярных выражений.

Конечно, но, учитывая произвольное форматирование, если мой стог сена содержал "(027) 123 456" (помните, что положение пробелов может меняться, это может быть так же легко 027 12 3456, и я хотел бы сопоставить его с 027123456, будет ли мой regex поэтому должен быть этим?

"^[\D]+0[\D]+2[\D]+7[\D]+1[\D]+2[\D]+3[\D]+4[\D]+5[\D]+6$"

(на самом деле это было бы хуже, поскольку руководство mysql, похоже, не указывает, что оно поддерживает \D)

Если это так, не более или менее то же самое, что и моя идея %%%%%?

Ответ 10

Просто идея, но вы не могли бы использовать Regex для быстрого выделения символов, а затем сравнить с тем, что предложил @Matt Hamilton?

Может быть, даже настроить представление (не уверенное в mysql on views), которое удерживало бы все номера телефонов, разделенные регулярным выражением, на простой номер телефона?

Ответ 11

Горе мне. Я закончил это:

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

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

Ответ 12

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

Ответ 13

возможное решение можно найти по адресу http://udf-regexp.php-baustelle.de/trac/

необходимо установить дополнительный пакет, затем вы можете играть с REGEXP_REPLACE

Ответ 14

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

Ответ 15

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