ORA-01830 Ошибка функции to_date, если поле содержит более 5 цифр - PullRequest
0 голосов
/ 28 июня 2018

У меня есть оператор SQL большего размера, который прекрасно работает, пока поле, отображающее среднюю продолжительность, не содержит более 5 цифр в используемом поле для отображения (B.AGGAVG)

to_char(to_date(ROUND(B.AGGAVG), 'SSSSS'), 'HH24:MI:SS') Mittlere_Dauer,

Эта строка вызывает сбой ORA, потому что без его работы нормально.

Он также работает нормально, если B.AGGAVG содержит не более 5 цифр.

1 Ответ

0 голосов
/ 28 июня 2018

Модель формата SSSSS представляет количество секунд после полуночи в дне, поэтому она не может принимать значения 86400 или выше. Вы получите «ORA-01830: изображение формата даты заканчивается перед преобразованием всей входной строки» для значений с более чем пятью цифрами, но вы также получите «ORA-01853: секунды в дне должны быть между 0 и 86399» для значений между 86400 и 99999.

То, как вы справитесь с этим, зависит от того, какой результат вы хотите получить. Вы можете преобразовать количество секунд в интервальный тип данных; принимая произвольное значение 250000 секунд:

select numtodsinterval(250000, 'SECOND') as result
from dual;

RESULT             
-------------------
+02 21:26:40.000000

но вы не можете напрямую отформатировать их. Или вы можете вручную деконструировать число в компоненты времени (на основе количества секунд в дне) и объединить их в строку:

select trunc(250000/86400)
  ||' '|| trunc(mod(250000, 86400)/3600)
  ||':'|| trunc(mod(250000, 3600)/60)
  ||':'|| mod(250000, 60) result
from dual;

RESULT    
----------
2 21:26:40

Если вам не нужно отдельное количество дней, то вместо обычного ручного подхода вы можете получить общее количество часов (которое может быть больше 24):

select trunc(250000/3600)
  ||':'|| trunc(mod(250000, 3600)/60)
  ||':'|| mod(250000, 60) result
from dual;

RESULT  
--------
69:26:40

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

select to_char(date '1970-01-01' + (250000/86400) - 1, 'FMDDD FMHH24:MI:SS') as result
from dual;

RESULT    
----------
2 21:26:40

Проблема в том, что -1 имеет дело с юлианской датой, начиная с 1, а не с нуля. С более коротким значением, которое идет немного не так:

select to_char(date '1970-01-01' + (1000/86400) - 1, 'FMDDD FMHH24:MI:SS') as result
from dual;

RESULT      
------------
365 00:16:40

, с которой вы могли бы иметь дело с дополнительной логикой, например изменение модели формата на основе исходного значения, чтобы оно показывало только количество дней для больших значений и фиксированный ноль (или ничего) для меньших значений:

select to_char(date '1970-01-01' + (1000/86400) - 1,
  case when 1000 >= 86400 then 'FMDDD FMHH24:MI:SS' else '"0" HH24:MI:SS' end) as result
from dual;

RESULT                                                                     
---------------------------------------------------------------------------
0 00:16:40

или если вы не хотите ноль:

select to_char(date '1970-01-01' + (1000/86400) - 1,
  case when 1000 >= 86400 then 'FMDDD FMHH24:MI:SS' else 'HH24:MI:SS' end) as result
from dual;

RESULT                                                                     
---------------------------------------------------------------------------
00:16:40

... но это, вероятно, не стоит усилий.


Какой бы подход вы ни использовали, кто / что потребляет, он должен уметь справляться и понимать, какую ценность он представляет.


Демонстрация различных исходных значений из CTE, показывающая вывод всех вышеперечисленных методов:

with b (aggavg) as (
  select 0 from dual
  union all select 0.123 from dual
  union all select 10 from dual
  union all select 100 from dual
  union all select 1000 from dual
  union all select 10000 from dual
  union all select 86399 from dual
  union all select 86400 from dual
  union all select 100000 from dual
  union all select 250000 from dual
  union all select 1000000 from dual
)
select b.aggavg,
  numtodsinterval(round(b.aggavg), 'SECOND') as result1,
  trunc(round(b.aggavg)/86400)
    ||' '|| trunc(mod(round(b.aggavg), 86400)/3600)
    ||':'|| trunc(mod(round(b.aggavg), 3600)/60)
    ||':'|| mod(round(b.aggavg), 60) result2,
  trunc(round(b.aggavg)/3600)
    ||':'|| trunc(mod(round(b.aggavg), 3600)/60)
    ||':'|| mod(round(b.aggavg), 60) result3,
  to_char(date '1970-01-01' + (round(b.aggavg)/86400) - 1,
    case when round(b.aggavg) >= 86400 then 'FMDDD FMHH24:MI:SS'
                                       else '"0" HH24:MI:SS' end) as result4,
  to_char(date '1970-01-01' + (round(b.aggavg)/86400) - 1,
    case when round(b.aggavg) >= 86400 then 'FMDDD FMHH24:MI:SS'
                                       else 'HH24:MI:SS' end) as result5
from b;

    AGGAVG RESULT1             RESULT2     RESULT3     RESULT4     RESULT5    
---------- ------------------- ----------- ----------- ----------- -----------
         0 +00 00:00:00.000000 0 0:0:0     0:0:0       0 00:00:00  00:00:00   
      .123 +00 00:00:00.000000 0 0:0:0     0:0:0       0 00:00:00  00:00:00   
        10 +00 00:00:10.000000 0 0:0:10    0:0:10      0 00:00:10  00:00:10   
       100 +00 00:01:40.000000 0 0:1:40    0:1:40      0 00:01:40  00:01:40   
      1000 +00 00:16:40.000000 0 0:16:40   0:16:40     0 00:16:40  00:16:40   
     10000 +00 02:46:40.000000 0 2:46:40   2:46:40     0 02:46:40  02:46:40   
     86399 +00 23:59:59.000000 0 23:59:59  23:59:59    0 23:59:59  23:59:59   
     86400 +01 00:00:00.000000 1 0:0:0     24:0:0      1 00:00:00  1 00:00:00 
    100000 +01 03:46:40.000000 1 3:46:40   27:46:40    1 03:46:40  1 03:46:40 
    250000 +02 21:26:40.000000 2 21:26:40  69:26:40    2 21:26:40  2 21:26:40 
   1000000 +11 13:46:40.000000 11 13:46:40 277:46:40   11 13:46:40 11 13:46:40
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...