Вопрос

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

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'

Не будет ли это очень медленно?

Это было полезно?

Решение

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

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

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

Другие советы

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

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

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

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

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

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

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

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

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

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

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

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

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

Видеть

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

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

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

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

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

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

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

Если это так, то не совпадает ли это более или менее с моей идеей %%%%%?

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

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

Горе мне.В итоге я сделал это:

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

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

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

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

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

Создайте пользовательскую функцию для динамического создания регулярных выражений.

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;

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top