Как сопоставить код города в номере телефона с Informix SQL? - PullRequest
0 голосов
/ 05 февраля 2020

У меня есть пара столов. Один содержит набранные в телефонных номерах:

  num
  84951234567
  74957654321
  4951357246
  83855112345
  73855154321
  3855113524

Другой имеет коды городов:

  city_code      city_name
  495            Moscow
  38551          Kalmanka

Мне нужно получить следующее:

  num             call_from
  84951234567     Moscow
  74957654321     Moscow
  4951357246      Moscow
  83855112345     Kalmanka
  73855154321     Kalmanka
  3855113524      Kalmanka

Номер телефона с городом код всегда состоит из 10 цифр; ему может предшествовать 7 или 8 или ничего. Код города может содержать от 3 до 5 цифр. Num хранится как VARCHAR. Можно ли это решить с помощью SQL?

Ответы [ 5 ]

1 голос
/ 07 февраля 2020

Предполагая, что вы используете сервер Informix 14.10, а не более раннюю версию, такую ​​как 12.10 или 11.70 (или что-то более старое, которое не поддерживается), тогда вы можете рассмотреть:

WITH mapped_cities(city_code, city_name) AS
     (SELECT        city_code, city_name FROM city_codes
      UNION
      SELECT '7' || city_code, city_name FROM city_codes
      UNION
      SELECT '8' || city_code, city_name FROM city_codes
     )
SELECT d.num, m.city_name AS call_from
  FROM dialled_phone_numbers AS d
  JOIN mapped_cities AS m
    ON m.city_code = LEFT(d.num, LENGTH(m.city_code))

с примером таблицы и данные настраиваются с использованием следующего (некоторые данные из вопроса, некоторые данные из комментариев):

CREATE TABLE dialled_phone_numbers(num VARCHAR(11) NOT NULL PRIMARY KEY);
CREATE TABLE city_codes(city_code VARCHAR(5) NOT NULL PRIMARY KEY, city_name VARCHAR(25) NOT NULL);

INSERT INTO city_codes VALUES('812', 'St.Petersburg');
INSERT INTO city_codes VALUES('3812', 'Omsk');
INSERT INTO city_codes VALUES('495', 'Moscow');
INSERT INTO city_codes VALUES('38551', 'Kalmanka');

INSERT INTO dialled_phone_numbers VALUES('3812217715');
INSERT INTO dialled_phone_numbers VALUES('3855113524');
INSERT INTO dialled_phone_numbers VALUES('4951357246');
INSERT INTO dialled_phone_numbers VALUES('73855154321');
INSERT INTO dialled_phone_numbers VALUES('74957654321');
INSERT INTO dialled_phone_numbers VALUES('84951234567');

показанный запрос производит вывод:

num          call_from
VARCHAR(11)  VARCHAR(25)
3812217715   Omsk
3855113524   Kalmanka
4951357246   Moscow
73855154321  Kalmanka
74957654321  Moscow
84951234567  Moscow

Ясно, что Предложение ORDER BY может быть использовано для лучшей последовательности вещей.

Предложение WITH создает список префиксов с «ничем» или с 7 или 8 в качестве префикса. Затем это используется для объединения с началом чисел в таблице dialled_phone_numbers, используя условие соединения из первого сегмента кода в Гордон Линофф ответ .

Если у вас более старая версия Informix без предложения WITH (выражение общей таблицы или CTE), вы можете использовать временную таблицу для хранения результатов подзапроса UNION, использованного в предложении WITH, и присоединиться к нему. вместо этого.

1 голос
/ 06 февраля 2020

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

SELECT p.num, c.city_name
  FROM phones p, cities c
 WHERE LEFT(p.num, LENGTH(c.city_code)+1) MATCHES "*" || c.city_code || "*"

Поскольку может быть префикс перед кодом города в номере телефона, я беру подстроку длины (код города) + 1

* Редактировать *

Я делаю соединение с outer, чтобы выбрать телефоны без кода города, и поскольку телефон с кодом города всегда состоит из 10 цифр, сначала я подставляю последние 10 цифр телефона (как показано на рисунке) в другом ответе)

SELECT p.num, c.city_name
  FROM phones p, OUTER cities c
 WHERE c.city_code = LEFT(RIGHT(p.num, 10), LENGTH(c.city_code))
1 голос
/ 05 февраля 2020

Это боль делать эффективно. Предполагая, что коды городов не имеют префиксов друг друга (например, «123» и «1234»), вы можете попробовать:

select d.*, c.city_name
from dialedin d join
     cities c
     on c.citycode = left(d.num, length(citycode))

Это может быть неоптимально, потому что left() имеет столбцы из обе таблицы, и это, как правило, исключает использование индекса. Альтернатива - множественные объединения:

select d.*, coalesce(c3.city_name, c4.city_name, c5.city_name)
from dialedin d left join
     cities c3
     on c3.citycode = left(d.num, 3) left join
     cities c4
     on c4.citycode = left(d.num, 4) left join
     cities c5
     on c5.citycode = left(d.num, 5) 

Еще одно преимущество подхода с несколькими join состоит в том, что вы можете взять самый длинный префикс, который соответствует:

select d.*, coalesce(c3.city_name, c4.city_name, c5.city_name)
from dialedin d left join
     cities c5
     on c3.citycode = left(d.num, 5) left join
     cities c4
     on c4.citycode = left(d.num, 4) and c5.citycode is null left join
     cities c3
     on c5.citycode = left(d.num, 3) and c4.citycode is null
0 голосов
/ 07 февраля 2020

Вас интересуют

  • все 10-значные git числа
  • все 11-значные git числа, начинающиеся с 7
  • все 11 -di git числа, начинающиеся с 8

Выберите эти и внешние присоединения к городам (или присоединитесь к внутренним, если вы только хотите видеть совпадения или даже видеть, что гарантировано, что вы получаете только совпадения) :

select
  p.phone_number,
  c.city
from phonecalls p
left join cities c on right(p.phone_number, 10) like c.city_code || '%'
where length(p.phone_number) = 10
or (length(p.phone_number) = 11 and p.phone_number like '7%')
or (length(p.phone_number) = 11 and p.phone_number like '8%')
order by c.city, right(p.phone_number, 10), p.phone_number;

(Если это слишком медленно, вы можете написать пользовательскую функцию, чтобы получить число 10-ди git из этих 10/11-ди git и создать индекс функции для этого. Запрос будет читать что-то вроде select ... join cities c on ten_digit_number(p.phone_number) like c.city_code || '%' ... where ten_digit_number(p.phone_number) is not null.)

0 голосов
/ 05 февраля 2020

В качестве решения, упомянутого Полом в комментариях, вы также можете изменить его на

        JOIN ON city_code = LEFT(num, 5) or city_code = LEFT(num, 3)

РЕДАКТИРОВАТЬ

Давайте рассмотрим возможный сценарий ios. Если у вас есть максимум 5 di git код, а также префикс с номером 7 или 8, то всего будет 6 цифр. Ваше обобщенное предложение join будет

       JOIN ON LEFT(num, 6) LIKE '%'+city_code+'%'

Надеюсь, это сработает.

...