我有一个较大的SQL语句,它工作正常,直到显示中位数持续时间的字段在用于显示的字段(B.AGGAVG)中包含5个以上数字为止
to_char(to_date(ROUND(B.AGGAVG), 'SSSSS'), 'HH24:MI:SS') Mittlere_Dauer,
此行导致ORA失败,因为无法正常工作。
只要B.AGGAVG最多包含5位数字,它就可以正常工作。
答案 0 :(得分:2)
The SSSSS
format model represents是一天中午夜之后的秒数,因此它不能接受86400或更高的值。对于五位数以上的值,您将获得“ ORA-01830:日期格式图片在转换整个输入字符串之前结束”,对于86400之间的值,您还将获得“ ORA-01853:一天中的秒数必须在0到86399之间”和99999。
如何处理此问题取决于您希望得到的结果。您可以将秒数转换为间隔数据类型。取值为250,000秒的任意值:
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