Алгоритм для поиска номера по маске

Не могу придумать как организовать поиск по маске телефона в mysql.

Есть таблица, хранящая номера мобильных телефонов (всегда 10 цифр) — примерно 2 миллиона записей.
Нужно организовать поиск по этим номерам с помощью масок: маска также всегда состоит из 10 символов, в которых:
1) цифры 0..9 — означают что на этом месте стоит цифра
2) X — означает что может быть любая цифра
3) A,B,C,D — цифры, отличные друг от друга (A не равно B, B не равно С, ...).

Например если маска 911-AAA-X-BBB, то под неё попадают номера:
911-000-0-111
911-000-0-222
911-000-0-333

911-000-0-999
911-111-0-000
911-111-0-222
и т.д.
но не попадают номера
911-001-0-222 (все вхождения буквы А должны соот. одной цифре)
911-111-0-111 (A не должно быть равно В)

Пробовал сделать с помощью regexp, но вроде там нельзя реализовать логику что A!=B или что все вхождения A имеют одну и ту же цифру.
  • Вопрос задан
  • 6985 просмотров
Решения вопроса 1
@balloon
Не придумал как сделать через одну регулярку, но можно попробовать следующее:

1. Сгенерировать общую регулярку.
Для 911-AAA-X-BBB это будет выглядеть как 911-(000|111|222|...|999)-[0-9]-(000|111|222|...|999)

2. Сделать сравнение блоков A,B,C,D через подстроки.
Для 911-AAA-X-BBB это будет выглядеть как SUBSTRING(phone,5,3) != SUBSTRING(phone,11,3)
Ответ написан
Пригласить эксперта
Ответы на вопрос 5
Dzuba
@Dzuba
Имею 2 варианта:

Вариант 1. Хранить сами номера телефонов «поциферно» — в 10 полях таблицы (D0, D1, ..., D9), по 1 полю на каждую цифру номера. Произвести индексацию по этим полям.
Плюсы: при поиске будут использоваться индексы.
Минусы: растет размер таблицы, растет время обновления данных при вставке/замене и т.д.
Пример для маски 911-AAA-X-BBB:
SELECT * FROM table WHERE D0=9 AND D1=1 AND D2=1 AND D3=D4 AND D4=D5 AND D7=D8 AND D8=D9


Вариант 2. При вводе маски (в основной программе) заранее подготовить список ВСЕХ (не обязательно содержащихся в таблице) номеров, удовлетворяющих маске, и использовать уже этот список в WHERE.
Плюсы: при поиске будет использоваться индекс.
Минусы: при «слабой» маске, таких номеров в списке может оказаться довольно много и сам текст запроса получится невообразимо большим.
Этот метод будет хорош, когда маска «сильная», например: 911-AAAAAA-X (всего порядка 100 вариантов)
Пример для маски 911-AAA-X-BBB:
SELECT * FROM table WHERE phone IN (9110001111, 9110001222, 9110001333, ...)
Ответ написан
ertaquo
@ertaquo
Попробуйте использовать регулярные выражения. А именно, \d{3}-\d{3}-\d-\d{3}
Ответ написан
@Voron095
Системный администратор, аналитик, архитектор...
911-(0{3}|1{3}|2{3}|3{3}|4{3}|5{3}|6{3}|7{3}|8{3}|9{3})-X-(0{3}|1{3}|2{3}|3{3}|4{3}|5{3}|6{3}|7{3}|8{3}|9{3})
я бы использовал такой вариант, на большее я незнаю
а вот на счет проверки что AAA =! BBB если только выдирать из номера и сравнивать их отдельно, но тут у меня возникает есть ли смысл делать это базой, я не спец в этом
Ответ написан
Dzuba
@Dzuba
Да, прошляпил один момент — в первом варианте нужно добавить условие, что A != B. С ним запрос будет выглядеть, например, так:
SELECT * FROM table WHERE D0=9 AND D1=1 AND D2=1 AND D3=D4 AND D4=D5 AND D7=D8 AND D8=D9 AND D3!=D7
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы