Oracle PL / SQL - Проверка числовых форматов и масок - PullRequest
0 голосов
/ 26 февраля 2020

После долгого времени без выполнения PL / SQL ... Мне нужно предложение от сообщества, что-то, что очевидно тривиально, но я немного застрял в этом.

Я построение загрузки из файла CSV, и там у нас есть столбец с количеством. CSV приходят от разных поставщиков, и каждый может отправить сумму в разных форматах. Поэтому я должен отклонить строки из CSV с суммой, которая не в правильном числовом формате (999 999 999 999,00), потому что поставщик может указывать неверную сумму и должен быть исправлен.

Исходя из форматов 999.999.999, 00 или 999999999,99, я могу сделать некоторые процедуры через PL / SQL для преобразования. Но у меня проблемы со значениями в разных форматах, таких как 999,9,9,9 или что-то еще ...

Я пытаюсь использовать общие функции (TO_NUMBER, TO_CHAR). Но без особого успеха ...

  1. SELECT TO_NUMBER('999,9,9,9') FROM DUAL; или SELECT TO_NUMBER('999,9,9,9','99G990G990G990G990G990D00') FROM DUAL;

Результат ORA-01722: недопустимый номер, и это блестяще! Тем не менее, он будет отклонять другие форматы, которые кажутся правильными, как 9,999,99

SELECT TO_NUMBER('999,9,9,9','99G999G999G999G999G999D00') FROM DUAL;

Используя маску формата, значение 999,9,9,9 преобразуется в 999999 - и это не нормально. Однако использование маски формата работает, например, для 9 999,99

Знаете ли вы какие-либо другие функции, предоставляемые Oracle, которые могут помочь решить мою проблему?

Или какие-либо предложения о том, как я могу сделать это?

Большое спасибо.

Атт.,

Гильерме

1 Ответ

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

Вы можете использовать регулярное выражение для определения правильного числа или нет. Затем, если он действителен, замените запятую нулями, а затем преобразуйте ее в число. В приведенных ниже запросах используется следующее регулярное выражение:

'^(\d{1,3})(\,\d{3})*(\.\d{2}|\.?)$'

Разбивается следующим образом

  • ^ (\ d {1,3}) --- в начале строки 1-3 цифры
  • (\, \ d {3}) * --- с последующим 0 или более запятыми, за которыми следуют 3 цифры
  • (. \ D {2} |.?) --- с последующим десятичным знаком и двумя цифрами ИЛИ (|) необязательный десятичный знак
  • $ --- конец строки

Демонстрация:

with test (num, expected)
   as (select '999,999,999,999.00', 'valid'    from dual union all
       select '999,99,999,999.00',  'invalid'  from dual union all 
       select '999.00',             'valid'    from dual union all 
       select '99',                 'valid'    from dual union all 
       select '9,999.',             'valid'    from dual union all 
       select '9,999..0',           'invalid'  from dual union all         
       select '999,99999,999.00',   'invalid'  from dual  
      )
select num
     , expected
     , case when regexp_like(num,'^(\d{1,3})(\,\d{3})*(\.\d{2}|\.?)$')   
            then to_char(to_number(replace(num,',',null)))
            else 'Not Valid Number'
       end converted
  from test;

В режиме реального времени вам не нужна структура "to_char (to_number ..."). Это использовалось для демонстрации / тестирования, так как и тогда, и тогда оператор case должен приводить к одному и тому же типу данных. Живая версия будет выглядеть примерно так:

with test (num)
   as (select '999,999,999,999.00'  from dual union all
       select '999,99,999,999.00'   from dual union all 
       select '999.00'              from dual union all 
       select '99'                  from dual union all 
       select '9,999.'              from dual union all 
       select '9,999..0'            from dual union all         
       select '999,99999,999.00'    from dual  
      )
select to_number(replace(num, ',', null))
  from test
 where regexp_like(num,'^(\d{1,3})(\,\d{3})*(\.\d{2}|\.?)$');  
...