Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Пятничные телефонные маски  [new]
slow brain
Member

Откуда:
Сообщений: 284
Добрый день. Столкнулся тут с задачкой, выношу на суд общественности

Есть некая система, которая работает с телефонными номерами. Система позволяет задвать маску для поля.
В записи маски используются следующие правила:
  • 9 - на этом месте указывается цифра
  • \<символ> - константный символ
    Таким образом, для телефона РФ маска может быть записана в виде
    \+\7\(999\)999\-99\-99 или 999\-999\-99\-99 или \9\-\8\-9999999999\; 

    Задача 1 - запросом отформатировать сохраненные телефонные номера по маске. Запрос должен работать для произвольной маски, записанной по правилам (рассматриваем только номера РФ, записанные в формате 10 цифр, например, 4959009876 или 8005554212, корректность маски и проверять не нужно - это обеспечивает система)

    SQL>   with m as (select '\+\7\(999\)999\-99\-99' mask, '4959009876' num from dual)
    ...
    ...
    ...
     14  select phone_num from (
    ...
     16  );
    
    PHONE_NUM
    --------------------------------------------------------------------------------
    +7(495)900-98-76
    


    Задача 2 - запросом убрать маску с номеров, записанных в формате маски (система передает номера в соответствии с маской, проверять на корректность не требуется - т.е. +7(495)900-98-76 преобразовать в 4959009876). Запрос так же должен работать для произвольной маски.

    SQL>   with m as (select '\+\7\(999\)999\-99\-99' mask, '+7(495)900-98-76' phone_num from dual)
    ...
    ...
    ...
     10  select num from (
    ...
     12  );
    
    NUM
    --------------------------------------------------------------------------------
    4959009876
    
    SQL>
    
  • 6 окт 17, 12:43    [20847899]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    Elic
    Member

    Откуда: 1984. Выбраковка финно-угром началась. КЯЗ
    Сообщений: 27498
    slow brain
    Задача 2
    select regexp_substr(regexp_replace('+7(495)900-98-76', '\D'), '\d{10}$') as n from dual;
    
    N
    ----------
    4959009876
    
    6 окт 17, 12:54    [20847937]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    slow brain
    Member

    Откуда:
    Сообщений: 284
    Elic,
    красиво, но если добрый пользователь вколотит маску с цифровой константой на конце - не сработает
    SQL>   with m as (select '\+\7\(999\)999\-99\-99\;\1' mask, '+7(495)900-98-76;1' phone_num from dual)
    ..
    ..
    ..
     10  select num from (
    ...
     12);
    
    NUM
    --------------------------------------------------------------------------------
    4959009876
    
    6 окт 17, 13:03    [20847979]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    AmKad
    Member

    Откуда:
    Сообщений: 4690
    slow brain
    Elic,
    красиво, но если добрый пользователь вколотит маску с цифровой константой на конце - не сработает
    Но ведь ты сказал, что маски всего три и корректность введенного телефона проверяется "системой".
    6 окт 17, 13:12    [20848015]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    slow brain
    Member

    Откуда:
    Сообщений: 284
    slow brain
    Запрос должен работать для произвольной маски, записанной по правилам

    То что я привел - это лишь примеры, этим фантазия не ограничивается.

    По задаче 2 кстати я нашел два разных варианта. regexp есть в обоих, но они принципиально разные
    6 окт 17, 13:16    [20848037]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    slow brain
    Member

    Откуда:
    Сообщений: 284
    AmKad
    Но ведь ты сказал, что маски всего три и корректность введенного телефона проверяется "системой".

    корректность в том, что не требуется проверять синтаксис маски на корректность, а так же
  • в задаче 1 не требуется проверять число значащих позиций в маске и в номере - они совпадают (если не совпадает, оно отбрасывается ранее)
  • в задаче 2 не требуется проверять совпадение входных данных с маской - как раз это и обеспечивает система.
  • 6 окт 17, 13:23    [20848064]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    AmKad
    Member

    Откуда:
    Сообщений: 4690
    slow brain,

    Нужно четкое и непротиворечивое описание как и что парсить. И примеры. Лично я пока ничего не понял .
    6 окт 17, 13:30    [20848110]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    slow brain
    Member

    Откуда:
    Сообщений: 284
    AmKad,
    мне показалось что описано нормально.
    Суть - номер записанный как 10 цифр отобразить в виде, задающемся маской, и наоборот, если номер записан по маске, включая разные доп. символы (в т.ч. они могут быть цифровыми и в произвольных местах) - эти доп.символы убрать. В маске символ "9" обозначает позицию цифры, экранирующий \ обозначает символ, следующий за ним, как есть. Маска может быть произвольной абсолютно, но должна записываться по правилам (т.е. любой символ не являющийся "9" экранируется, "9" может быть заэкранирована)
    6 окт 17, 13:41    [20848159]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    slow brain
    Member

    Откуда:
    Сообщений: 284
    Примеры:
     with m as (select '999\-999\-99\-99' mask, '4959009876' num from dual)
    ..
    select phone_num from (              
    );
    
    495-900-98-76
    
    with m as (select '\9\-\8\-9999999999\;' mask, '4959009876' num from dual)
    ..
    select phone_num from (              
    );
    
    9-8-4959009876;
    
    with m as (select '\+\7\(999\)999\-99\-99\;\1' mask, '4959009876' num from dual)
    ..
    select phone_num from (              
    );
    
    +7(495)900-98-76;1
    

    В обратную сторону думаю понятно.
    6 окт 17, 13:51    [20848231]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    SY
    Member

    Откуда: Middlebury, CT USA
    Сообщений: 8683
    slow brain
    Elic,
    красиво, но если добрый пользователь вколотит маску с цифровой константой на конце - не сработает


    Задачу нужно озвучивать внятно. Да и непонятно с какого бодуна цифры будут использоваться как разделители. Ну да ладно. Если число групп <= 9:

    with m as (
               select '999\-999\-99\-99' mask, '495-900-98-76' phone_num from dual union all
               select '\9\-\8\-9999999999\;' mask, '9-8-4959009876;' phone_num from dual union all
               select '\+\7\(999\)999\-99\-99\;\1' mask, '+7(495)900-98-76;1' phone_num from dual
              )
    select  mask,
            phone_num,
            regexp_replace(
                           phone_num,
                           regexp_replace(regexp_replace(mask,'\\.','.'),'9+','(\d+)'),
                           '\1\2\3\4\5\6\7\8\9'
                          ) num
      from  m
    /
    
    MASK                       PHONE_NUM            NUM
    -------------------------- -------------------- ----------
    999\-999\-99\-99           495-900-98-76        4959009876
    \9\-\8\-9999999999\;       9-8-4959009876;      4959009876
    \+\7\(999\)999\-99\-99\;\1 +7(495)900-98-76;1   4959009876
    
    SQL> 
    


    SY.
    6 окт 17, 14:54    [20848602]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    dbms_photoshop
    Member

    Откуда: sqlmdx.net
    Сообщений: 4902
    slow brain
    Задача 2
    Думаю из-за ограничений оракловых регулярок без разбиения строки в том или ином виде не решается для числа групп девяток более 9.

    Соотвественно, либо посимвольное разбиение либо выдирание групп девяток из исходного номера подшаманив над маской.

    SQL> with m as
      2  (select 1 id, '\+\7\(999\)999\-99\-99' mask, '+7(495)900-98-76' phone_num from dual
      3  union all select 2 id, '\+\7\(999\)999\-99\-99\;\1' mask, '+7(495)900-98-76;1' phone_num from dual
      4  )
      5  select *
      6  from m
      7  model
      8  partition by (id)
      9  dimension by (1 dummy)
     10  measures (replace(mask, '\') mask, phone_num, cast(null as varchar2(240)) result)
     11  rules iterate(1e9) until (substr(mask[1], iteration_number + 1, 1) is null)
     12  (
     13    result[1] = decode(substr(mask[1], iteration_number + 1, 1), '9',
     14                       result[1] || substr(phone_num[1], iteration_number + 1, 1), result[1])
     15  );
    
            ID      DUMMY MASK                       PHONE_NUM          RESULT
    ---------- ---------- -------------------------- ------------------ --------------------
             1          1 +7(999)999-99-99           +7(495)900-98-76   4959009876
             2          1 +7(999)999-99-99;1         +7(495)900-98-76;1 4959009876
    
    SQL> with m as
      2  (select 1 id, '\+\7\(999\)999\-99\-99' mask, '+7(495)900-98-76' phone_num from dual
      3  union all select 2 id, '\+\7\(999\)999\-99\-99\;\1' mask, '+7(495)900-98-76;1' phone_num from dual
      4  )
      5  select id,
      6         listagg(regexp_substr(phone_num_mod, mask_mod, 1, 1, null, level)) within group (order by level) result
      7    from (select id,
      8                 translate(phone_num, '()', '##') phone_num_mod,
      9                 regexp_replace(regexp_replace(translate(mask, '()\', '##'), '(9+)', '(\1)'), '[^()]', '.') mask_mod
     10            from m)
     11  connect by prior id = id and level <= regexp_count(mask_mod, '\(') and prior sys_guid() is not null
     12  group by id;
    
            ID RESULT
    ---------- --------------------
             1 4959009876
             2 4959009876
    
    6 окт 17, 15:15    [20848685]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    slow brain
    Member

    Откуда:
    Сообщений: 284
    Со второй задачей почти разобрались

    способ №2 - чисто на regexp (я его сделал позже способа №1) - влоб с подсчетом количества групп

      with m as (select '\+\7\(999\)999\-99\-99\-\1' mask, '+7(495)900-98-76-1' phone_num from dual)
         , fmt1 as (select phone_num, replace(replace(regexp_replace(mask, '\\.','.'),'9','(\d)'),')(') mask_str from m)
         , fmt as (select phone_num
                        , mask_str
                        , listagg(txt,'') within group(order by txt) format_str
                     from fmt1
                        , (select '\'||rownum txt from fmt1 connect by level <= regexp_count(mask_str,'\(')) 
                    group by phone_num, mask_str
                   )
    select num from (               
    select regexp_replace(phone_num, mask_str, format_str) num from fmt);  
    


    А отсюда и до решения задачи 1 недалеко

    dbms_photoshop
    Думаю из-за ограничений оракловых регулярок без разбиения строки в том или ином виде не решается для числа групп девяток более 9.

    Это был способ №1 - я его придумал раньше - просто вспомнив что поняте "маска" может трактоваться как "битовая маска" - и он не имеет ограчиней на группы
      with m as (
               select '999\-999\-99\-99' mask, '495-900-98-76' phone_num from dual union all
               select '\9\-\8\-9999999999\;' mask, '9-8-4959009876;' phone_num from dual union all
               select '\+\7\(999\)999\-99\-99\;\1' mask, '+7(495)900-98-76;1' phone_num from dual
              )
    select  mask,
            phone_num,
            replace(utl_raw.cast_to_varchar2(utl_raw.bit_and(utl_raw.cast_to_raw(phone_num),utl_raw.cast_to_raw(replace(regexp_replace(mask, '\\.',chr(0)),'9',chr(255))))), chr(0)) 
        from m
    
    6 окт 17, 15:38    [20848744]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    dbms_photoshop
    Member

    Откуда: sqlmdx.net
    Сообщений: 4902
    slow brain
    чисто на regexp
    разрезать и склеить значит "чисто на regexp"?

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

    Использование встроенных PL/SQL пакетов для RAW - тоже просто замыливание глаз.
    6 окт 17, 15:48    [20848776]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    slow brain
    Member

    Откуда:
    Сообщений: 284
    Свое решение по задаче №1 я опубликую в понедельник.
    6 окт 17, 16:52    [20849026]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    rpovarov
    Member

    Откуда:
    Сообщений: 37
    #1 в лоб :)

    Не решал пока вариант c '\\', финальный replace можно заменить каким-нибудь хитрым регекспом.

    with mask (id, mask, num) as (
      select 1, '999\-999\-99\-99', '4959009876' from dual
      union all
      select 2, '\+\7\(999\)999\-99\-99\;\1', '4959009876' from dual
      union all
      select 3, '\9\-\8\-9999999999\;', '4959009876' from dual
    ),
    parse(id, mask, num, lvl, msk) as (
      select 
        id, mask, num, 1, regexp_replace(mask, '9{1}', substr(num, 1, 1), instr(replace(mask, '\9', '\x'), '9', 1, 1), 1) msk
      from mask m
      union all
      select 
        m.id, m.mask, m.num, p.lvl+1, regexp_replace(p.msk, '9{1}', substr(m.num, p.lvl+1, 1), instr(replace(m.mask, '\9', '\x'), '9', 1, p.lvl+1), 1) msk 
      from parse p
      join mask m on m.id = p.id and p.lvl+1 <= length(m.num)
    )
    select 
      mask, num, replace(msk, '\', '') as result
    from parse
    where lvl = length(num);
    
    6 окт 17, 17:31    [20849151]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    SY
    Member

    Откуда: Middlebury, CT USA
    Сообщений: 8683
    slow brain
    Со второй задачей почти разобрались

    способ №2 - чисто на regexp (я его сделал позже способа №1) - влоб с подсчетом количества групп

      with m as (select '\+\7\(999\)999\-99\-99\-\1' mask, '+7(495)900-98-76-1' phone_num from dual)
         , fmt1 as (select phone_num, replace(replace(regexp_replace(mask, '\\.','.'),'9','(\d)'),')(') mask_str from m)
         , fmt as (select phone_num
                        , mask_str
                        , listagg(txt,'') within group(order by txt) format_str
                     from fmt1
                        , (select '\'||rownum txt from fmt1 connect by level <= regexp_count(mask_str,'\(')) 
                    group by phone_num, mask_str
                   )
    select num from (               
    select regexp_replace(phone_num, mask_str, format_str) num from fmt);  
    




    Ты слишком усложнил - весь этот listagg совершенно не нужeн. Ссылка на несуществующий backreference замещается NULL, так-что достаточно '\1\2\3\4\5\6\7\8\9'. И группы из одной цифры создавать тоже ненужно - их ведь может быть всего 9.
    Используй не (9) --> (\d) a (9+) --> (\d+) как в моем примере:

            regexp_replace(
                           phone_num,
                           regexp_replace(regexp_replace(mask,'\\.','.'),'9+','(\d+)'),
                           '\1\2\3\4\5\6\7\8\9'
                          ) num
    


    SY.
    6 окт 17, 18:13    [20849294]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    slow brain
    Member

    Откуда:
    Сообщений: 284
    SY,
    Именно твой вариант я бы запустил, если бы задачу внезапно не сняли :)

    rpovarov, слишком перегружено.
    6 окт 17, 18:53    [20849402]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    SY
    Member

    Откуда: Middlebury, CT USA
    Сообщений: 8683
    slow brain
    Свое решение по задаче №1 я опубликую в понедельник.


    with m as (
               select '999\-999\-99\-99' mask, '4959009876' num from dual union all
               select '\9\-\8\-9999999999\;' mask, '4959009876' num from dual union all
               select '\+\7\(999\)999\-99\-99\;\1' mask, '4959009876' num from dual
              ),
        r(
          mask,
          num,
          phone_num,
          mask_pos,
          num_pos
         ) as (
                select  mask,
                        num,
                        null phone_num,
                        0 mask_pos,
                        0 num_pos
                  from  m
               union all
                select  mask,
                        num,
                        case substr(mask,mask_pos + 1,1)
                          when '\' then phone_num || substr(mask,mask_pos + 2,1)
                          else phone_num || substr(num,num_pos + 1,1)
                        end phone_num,
                        case substr(mask,mask_pos + 1,1)
                          when '\' then mask_pos + 2
                          else mask_pos + 1
                        end mask_pos,
                        case substr(mask,mask_pos + 1,1)
                          when '\' then num_pos
                          else num_pos + 1
                        end num_pos
                  from  r
                  where mask_pos < length(mask)
              )
    select  mask,
            num,
            phone_num
      from  r
      where mask_pos = length(mask)
    /
    
    MASK                       NUM        PHONE_NUM
    -------------------------- ---------- --------------------
    999\-999\-99\-99           4959009876 495-900-98-76
    \9\-\8\-9999999999\;       4959009876 9-8-4959009876;
    \+\7\(999\)999\-99\-99\;\1 4959009876 +7(495)900-98-76;1
    
    SQL> 
    


    SY.
    6 окт 17, 20:29    [20849532]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    dbms_photoshop
    Member

    Откуда: sqlmdx.net
    Сообщений: 4902
    SY,

    А с какой целью публикуется сие?
    Я понимаю rpovarov может оттачивает мастерство с rec with, но в вашем случае в чем смысл?

    Если на SQL идет попытка натянуть не SQL задачу так давайте это сделаем еще самым бредовым способом?
    Если у нас есть 10 млн масок по 15 символов так давайте запихаем в workarea 150 млн строк и будем по ним бегать.
    Затем фильтранем набор последней итерации.
    Зато SQL.
    6 окт 17, 21:03    [20849582]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    SY
    Member

    Откуда: Middlebury, CT USA
    Сообщений: 8683
    dbms_photoshop
    Если у нас есть 10 млн масок по 15 символов так давайте запихаем в workarea 150 млн строк и будем по ним бегать.


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

    SY.
    7 окт 17, 02:12    [20850232]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    xtender
    Member

    Откуда: Мск
    Сообщений: 4686
    имхо тут только в лоб (баловался не глядя других постов кроме стартового):
    задача 1:
    + вариант 1
    with m as (select '\+\7\(999\)999\-99\-99' mask, '4959009876' num from dual)
    select
      regexp_replace(
         regexp_replace(
              mask
             ,'9(\\.)*9(\\.)*9(\\.)*9(\\.)*9(\\.)*9(\\.)*9(\\.)*9(\\.)*9(\\.)*9$'
             ,  substr(num,1,1)||'\1'
              ||substr(num,2,1)||'\2'
              ||substr(num,3,1)||'\3'
              ||substr(num,4,1)||'\4'
              ||substr(num,5,1)||'\5'
              ||substr(num,6,1)||'\6'
              ||substr(num,7,1)||'\7'
              ||substr(num,8,1)||'\8'
              ||substr(num,9,1)||'\9'
              ||substr(num,10,1)
           )
      ,'\\(.)','\1')
    from m;
    

    + вариант 2
    with m as (select '\+\7\(999\)999\-99\-99' mask, '4959009876' num from dual)
    select
     m.*
     ,regexp_replace(
         (select 
            listagg(
               regexp_replace(
                  regexp_substr(mask,'(\\.)*9',1,11-level)
                 ,'((\\.)*)(9)','\1'||substr(num,11-level,1)
               )
            )within group( order by level desc)
          from dual
          connect by level<=10)
         ,'\\(.)','\1'
      )
    from m
    
    + с to_char
    with m as (select '\+\7\(999\)999\-99\-99' mask, '4959009876' num from dual)
    select
     m.*
     ,regexp_replace(
         (select 
            listagg(
               to_char(
                 to_date(1000+substr(num,11-level,1),'yyyy')
                ,regexp_replace(
                   regexp_substr(mask,'(\\.)*9',1,11-level)
                  ,'((\\.)*)9','"\1"y'
                 )
               )
            )within group( order by level desc)
          from dual
          connect by level<=10)
         ,'\\(.)','\1'
      )
    from m;
    
    + c utl_lms гораздо проще
    with function format_number(p_mask in varchar2,p_num varchar2) return varchar2 
         as
         begin 
           return 
             regexp_replace(
               utl_lms.format_message(
                 regexp_replace(p_mask,'(\\.)*9','\1%s')
                ,substr(p_num, 1,1)
                ,substr(p_num, 2,1)
                ,substr(p_num, 3,1)
                ,substr(p_num, 4,1)
                ,substr(p_num, 5,1)
                ,substr(p_num, 6,1)
                ,substr(p_num, 7,1)
                ,substr(p_num, 8,1)
                ,substr(p_num, 9,1)
                ,substr(p_num,10,1)
              )
            ,'\\(.)'
            ,'\1'
           ); 
         end format_number;
      m as (select '\+\7\(999\)999\-99\-99' mask, '4959009876' num from dual)
    select
       m.*
      ,format_number(mask,num)
    from  m
    
    7 окт 17, 03:53    [20850247]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    rpovarov
    Member

    Откуда:
    Сообщений: 37
    dbms_photoshop
    SY,
    Я понимаю rpovarov может оттачивает мастерство с rec with

    Именно так. Балуюсь, пятничное же :)

    IMHO такие вещи надо вообще убирать из базы, пусть frontend (или какой другой потребитель) сам конвертирует. Или жёстко ограничивать на количество знаков, чтобы работали решения, которые показали SY и xtender. И потом бить ногами любого, кто придёт с идеей менять количество позиций.

    У меня на задания типа "...рассматриваем только номера РФ, записанные в формате 10 цифр..." срабатывает внутренний сигнал тревоги, потому что после подготовки красивого и элегантного решения с вероятностью 90% приходит вводная "формат может быть от 8 до 12 цифр". И надо переделывать, иногда полностью. Это не шпилька в сторону автора темы, просто из опыта работы.
    7 окт 17, 13:01    [20850696]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    rpovarov
    Member

    Откуда:
    Сообщений: 37
    Решение №1 с помощью MODEL (за образец взял код dbms_photoshop).
    - обрабатываются '\9' и '\\' (временной заменой на "непечатные" символы)
    - произвольное количество знаков (само собой, номер должен соответствовать маске)

    with m(id, mask, phone_num) as
    (
      select 1, '999\-999\-99\-99', '4959009876' from dual
      union all
      select 2, '\+\7\(999\)999\-99\-99\;\1', '4959009876' from dual
      union all
      select 3, '\9\-\8\-9999999999\;', '4959009876' from dual
      union all
      select 4, '\9\-\8\-9999999999999\;', '4959009876123' from dual
      union all
      select 5, '\\\9\-\8\-9999999\;', '4959009' from dual
      union all
      select 6, 'Типа номер и всё такое: \9\-\8\-9999999\;', '4959009' from dual
      )
    select 
        id, mask, phone_num, replace(replace(result, chr(254), '9'), chr(255), '\') as result
    from m
    model
        partition by (id)
        dimension by (0 dummy)
        measures (mask, replace(replace(replace(mask, '\9', chr(254)), '\\', chr(255)), '\') mask_filtered, phone_num, cast(null as varchar2(240)) result)
        rules iterate(1e9) until (substr(phone_num[0], iteration_number+2, 1) is null)
        (
            result[0] = regexp_replace(decode(iteration_number, 0, mask_filtered[0], result[0]), 
                                        '9', 
                                        substr(phone_num[0], iteration_number+1, 1), 
                                        instr(mask_filtered[0], '9', 1, iteration_number+1), 
                                        1
                                        )
        )
    order by id;    
    
    
            ID MASK                                                        PHONE_NUM     RESULT                                                                                                                                                                                                                                          
    ---------- ----------------------------------------------------------- ------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
             1 999\-999\-99\-99                                            4959009876    495-900-98-76                                                                                                                                                                                                                                   
             2 \+\7\(999\)999\-99\-99\;\1                                  4959009876    +7(495)900-98-76;1                                                                                                                                                                                                                              
             3 \9\-\8\-9999999999\;                                        4959009876    9-8-4959009876;                                                                                                                                                                                                                                 
             4 \9\-\8\-9999999999999\;                                     4959009876123 9-8-4959009876123;                                                                                                                                                                                                                              
             5 \\\9\-\8\-9999999\;                                         4959009       \9-8-4959009;                                                                                                                                                                                                                                   
             6 Типа номер и всё такое: \9\-\8\-9999999\;                   4959009       Типа номер и всё такое: 9-8-4959009;        
    
    8 окт 17, 17:36    [20852451]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    xtender
    Member

    Откуда: Мск
    Сообщений: 4686
    rpovarov,

    with m(id, mask, phone_num) as
    (
      select 1, '\\9999999', '4959009' from dual
      )
    select 
        id, mask, phone_num, replace(replace(result, chr(254), '9'), chr(255), '\') as result
    from m
    model
        partition by (id)
        dimension by (0 dummy)
        measures (mask, replace(replace(replace(mask, '\9', chr(254)), '\\', chr(255)), '\') mask_filtered, phone_num, cast(null as varchar2(240)) result)
        rules iterate(1e9) until (substr(phone_num[0], iteration_number+2, 1) is null)
        (
            result[0] = regexp_replace(decode(iteration_number, 0, mask_filtered[0], result[0]), 
                                        '9', 
                                        substr(phone_num[0], iteration_number+1, 1), 
                                        instr(mask_filtered[0], '9', 1, iteration_number+1), 
                                        1
                                        )
        )
    order by id;    
    ORA-01428: argument '0' is out of range
    
    8 окт 17, 17:45    [20852468]     Ответить | Цитировать Сообщить модератору
     Re: Пятничные телефонные маски  [new]
    rpovarov
    Member

    Откуда:
    Сообщений: 37
    xtender,

    Точно, спасибо. Надо поменять очерёдность // и /9.
    +
    with m(id, mask, phone_num) as
    (
      select 1, '\\9999999', '4959009' from dual
      )
    select 
        id, mask, phone_num, replace(replace(result, chr(254), '9'), chr(255), '\') as result
    from m
    model
        partition by (id)
        dimension by (0 dummy)
        measures (mask, replace(replace(replace(mask, '\\', chr(255)), '\9', chr(254)), '\') mask_filtered, phone_num, cast(null as varchar2(240)) result)
        rules iterate(1e9) until (substr(phone_num[0], iteration_number+2, 1) is null)
        (
            result[0] = regexp_replace(decode(iteration_number, 0, mask_filtered[0], result[0]), 
                                        '9', 
                                        substr(phone_num[0], iteration_number+1, 1), 
                                        instr(mask_filtered[0], '9', 1, iteration_number+1), 
                                        1
                                        )
        )
    order by id;    
    
            ID MASK      PHONE_N RESULT                                                                                                                                                                                                                                          
    ---------- --------- ------- -------------------------
             1 \\9999999 4959009 \4959009   
    
    8 окт 17, 19:13    [20852703]     Ответить | Цитировать Сообщить модератору
    Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
    Все форумы / Oracle Ответить