Преобразование формата диапазона номеров

Учитывая диапазон номеров сотовых телефонов в форме ['7810000000', '7819999999'], мне нужен алгоритм, который бы генерировал несколько строк наименьшей возможной длины, которые бы полностью покрывали заданный диапазон, если бы после них был добавлен символ "%". Например, диапазон сверху будет представлен в виде единой строки "781". Другими словами, любое число из диапазона может быть представлено как 781%. Это представление может быть полезно, например, для хранения тарифов. Одна строка в базе данных может быть использована для оценки всего диапазона. Есть много других задач, для которых предпочтительно иметь этот формат. Алгоритм для диапазона ['526251630000','526251634999'] даст

52625160
52625161
52625162
52625163
52625164

Для диапазона ['12300345','12367000'] мы должны получить

12300345
12300346
12300347
12300348
12300349
1230035
1230036
1230037
1230038
1230039
123004
123005
123006
123007
123008
123009
12301
12302
12303
12304
12305
12306
12307
12308
12309
1231
1232
1233
1234
1235
12361
12362
12363
12364
12365
12366
12367000

Нам нужно, чтобы это преобразование было сделано в Oracle(SQL/PLQSL). Любая информация или ссылки будут высоко оценены. Заранее спасибо.

1 ответ

Метод грубой силы, с диапазоном начала / конца в качестве переменных связывания:

var start_val varchar2(14);
var end_val varchar2(14);

exec :start_val := '526251630000';
exec :end_val := '526251634999';

with dns (dn) as (
  select to_number(:start_val) + level - 1
  from dual
  connect by level <= to_number(:end_val) - to_number(:start_val) + 1
),
exponents (ex) as (
  select level - 1 from dual
  connect by level <= length(:start_val)
),
tmp (dn, ex, pow, root, cnt ) as (
  select d.dn,
    e.ex,
    power(10, e.ex),
    trunc(d.dn / power(10, e.ex)),
    count(d.dn) over (partition by trunc(d.dn / power(10, e.ex)))
  from dns d
  cross join exponents e
)
select distinct to_char(min(root) keep (dense_rank first order by ex desc)
    over (partition by dn)) as result
from tmp
where pow = cnt
order by result;

который получает

RESULT                                  
----------------------------------------
526251630
526251631
526251632
526251633
526251634

dns CTE расширяет диапазон на все значения, которые он содержит. exponents CTE генерирует все возможные 10 степеней, которые вы, возможно, захотите использовать (т. Е. Сколько цифр выпадет справа от значения диапазона). tmp Затем CTE перекрестно объединяет их и подсчитывает, сколько отдельных чисел появляется в каждом "поддиапазоне", рассчитанном путем деления на степень 10. Затем в конечном запросе выполняется фильтрация по всем поддиапазонам, где число значений в этом диапазоне является такой же, как размер поддиапазона, поэтому нет пропущенных разбиений - и находит самый маленький (т.е. самый короткий) корень поддиапазона для каждого DN. И тогда, наконец, получает отличные значения тех.

Для второго диапазона:

exec :start_val := '12300345';
exec :end_val := '12367000';

тот же запрос получает:

RESULT                                  
----------------------------------------
12300345
12300346
12300347
12300348
12300349
1230035
1230036
1230037
1230038
1230039
123004
123005
123006
123007
123008
123009
12301
12302
12303
12304
12305
12306
12307
12308
12309
1231
1232
1233
1234
1235
12360
12361
12362
12363
12364
12365
12366
12367000

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

Я уверен, что есть более эффективные способы сделать это, и, надеюсь, кто-то придумает, но это может помочь вам начать.

Другие вопросы по тегам