ORA-01873:间隔的前导精度太小

时间:2017-04-20 06:17:08

标签: sql oracle

我得到一个ORA-01873"间隔的领先精度太小"此声明中的错误,无法找出原因:

v_not_auto_bl_num被声明为VARCHAR2(1000)

导致错误的原因是什么?

4 个答案:

答案 0 :(得分:1)

在您最初发布的代码中,您正在执行以下操作:

ABS( EXTRACT(DAY FROM (TO_TIMESTAMP(DHS.ASSIGNMENT_IODT,'YYYYMMDDHH24MISS.FF')
  - TO_TIMESTAMP(DHS.COMPLETED_IODT,'YYYYMMDDHH24MISS.FF')) *86400*1000) / 1000)

相关部分是:

(TO_TIMESTAMP(DHS.ASSIGNMENT_IODT,'YYYYMMDDHH24MISS.FF')
  - TO_TIMESTAMP(DHS.COMPLETED_IODT,'YYYYMMDDHH24MISS.FF')) *86400*1000

如果你减去两个时间戳,你会得到一个间隔数据类型,而不是一个数字;例如如果你的表格列是'20170419065416'和'20170419000000',那么减去它们会产生:

(TO_TIMESTAMP(DHS.A
-------------------
+00 06:54:16.000000

如果将其乘以86400 * 1000,则超出间隔数据类型的精度。我选择了这个值因为少了一秒就可以了:

with dhs (assignment_iodt, completed_iodt) as (
  select '20170419065415', '20170419000000' from dual
)
select (TO_TIMESTAMP(DHS.ASSIGNMENT_IODT,'YYYYMMDDHH24MISS.FF')
    - TO_TIMESTAMP(DHS.COMPLETED_IODT,'YYYYMMDDHH24MISS.FF')) as original,
  (TO_TIMESTAMP(DHS.ASSIGNMENT_IODT,'YYYYMMDDHH24MISS.FF')
    - TO_TIMESTAMP(DHS.COMPLETED_IODT,'YYYYMMDDHH24MISS.FF')) *86400*1000 as multiplied
from dhs;

ORIGINAL            MULTIPLIED               
------------------- -------------------------
+00 06:54:15.000000 +24855000 00:00:00.000000

再一次(或实际上,超过20170419065415.134814814的任何内容,或实际间隔高于06:54:15.134814814的任何值对)都会出错,因为相乘的时间间隔超出了数据类型的范围。

引擎盖下实际发生的事情尚不清楚;一旦越过原始间隔大小限制,使用较小的乘数也会导致问题。

无论如何,你似乎试图获得秒数,你可以通过提取每个时间元素并将它们相乘来实现:

select abs(
    (extract(day from diff) * 86400)
      + (extract (hour from diff) * 3600)
      + (extract (minute from diff) * 60)
      + trunc(extract (second from diff))
  ) as c_f_previous_time
from (
  select to_timestamp(dhs.assignment_iodt,'YYYYMMDDHH24MISS.FF')
    - to_timestamp(dhs.completed_iodt,'YYYYMMDDHH24MISS.FF') as diff
  from dhs
);

我已将时间戳减法放在内联视图中,因此不必在每次提取调用中重复。您可以将原始查询的其余部分放在内联视图(或CTE)中。

顺便提一下,abs()意味着你的表中可以有完成日期早于赋值的行;或者只是你没有注意到你正在以错误的方式进行减法。如果您在分配之前无法完成数据,那么您可以交换条款并丢失abs();我可能会交换条款,只是为了让它看起来更符合逻辑。

答案 1 :(得分:0)

首先尝试这个:

create table test_table as
SELECT ACT_BL.BL_NUM,
      ABS( EXTRACT(DAY FROM (TO_TIMESTAMP(DHS.ASSIGNMENT_IODT,'YYYYMMDDHH24MISS.FF') - TO_TIMESTAMP(DHS.COMPLETED_IODT,'YYYYMMDDHH24MISS.FF')) *86400*1000) / 1000) AS C_F_PREVIOUS_TIME
    FROM DOCI_ACTIVITY ACT ,
      DOCI_ACTIVITY_RELATED_BL ACT_BL ,
      DSH_ACTIVITY DHS
    WHERE ACTIVITY_TYPE   IN ('BlCodingAndFormatting','BlCreationFromESI')
    AND ACT.ACTIVITY_ID    =ACT_BL.ACTIVITY_ID
    AND ACT_BL.ACTIVITY_ID = DHS.ACTIVITY_ID
    AND ACT_BL.BL_NUM      = v_not_auto_bl_num;

然后检查 test_table 列类型( BL_NUM和C_F_PREVIOUS_TIME

之后

将这些列类型应用于表

答案 2 :(得分:0)

在您的情况下,将间隔乘以86400会引发异常。

我发布了here后,您可以使用以下较短的方法将时间间隔转换为毫秒。

SELECT ROUND((EXTRACT(DAY FROM (
    TO_TIMESTAMP(DHS.ASSIGNMENT_IODT,'YYYYMMDDHH24MISS.FF') - TO_TIMESTAMP(DHS.COMPLETED_IODT ,'YYYYMMDDHH24MISS.FF')
) * 24 * 60) * 60 + EXTRACT(SECOND FROM (
    TO_TIMESTAMP(DHS.ASSIGNMENT_IODT,'YYYYMMDDHH24MISS.FF') - TO_TIMESTAMP(DHS.COMPLETED_IODT ,'YYYYMMDDHH24MISS.FF')
))) * 1000) AS MILLIS FROM DUAL;

答案 3 :(得分:-1)

您的数字数字似乎太大,无法处理ABS功能。您可以传递给ABS()的最大值,因为数字是2 ^ 31-1: