Oracle 中日期、时间、时间戳或间隔文字的错误格式

Bad format for date, time, timestamp or interval literal in Oracle

我正在尝试检查我当前的时间戳是否介于两个时间戳之间。

我在我的 Oracle StoredProcedure 中使用以下查询

IF(SYSDATE BETWEEN TRUNC ( SYSDATE ) + INTERVAL '17:50' HOUR TO MINUTE AND TRUNC( SYSDATE ) + INTERVAL '18:30' HOUR TO MINUTE) THEN 

但它给我以下错误

Error(138,42): PLS-00166: bad format for date, time, timestamp or interval literal

我错过了什么吗?

trunc(sysdate) 是日期,而不是时间戳。不幸的是,Oracle 这种方式很奇怪:日期算法适用于数字(并且仅适用于数字),而时间戳适用于时间间隔。您不能对日期添加或减去间隔。

更糟:trunc(systimestamp) 是日期而不是时间戳!如果你想知道为什么,你将不得不问 Oracle;我不知道为什么。

虽然解决方案很简单。添加 17/24 + 50/(24*60).

而不是 interval '17:50' hour to minute

或者,您可以将 trunc(sysdate) 转换为时间戳:cast(trunc(sysdate) as timestamp) - 然后其余的应该工作。

ADDED:正如 OP 指出的那样,将 sysdate 转换为时间戳并不能解决问题。我再次尝试,使用不同的 INTERVAL 文字。虽然 INTERVAL '17:50' HOUR TO MINUTE 无效,但完整格式 INTERVAL '0 17:50:00' DAY TO SECOND 有效(!!!)似乎 PL/SQL 无法识别部分 INTERVAL 格式,需要完整的 DAY TO SECOND。要检查的东西 PL/SQL definition/documentation.

... 好的,在进一步查看 Oracle 文档后:没有具体提及不支持 HOUR TO MINUTE;但它没有出现在任何地方。仅提及DAY TO SECOND。 (一般来说,文档只会显示实现的内容,而不是未实现的内容,所以这在任何方面都不奇怪。)

在 PLSQL 中只能使用 DAY TO SECOND。 您可以使用以下其中一项:

begin
    IF(SYSDATE BETWEEN TRUNC(SYSDATE) + INTERVAL '0 16:00:00' DAY TO SECOND
                     AND TRUNC(SYSDATE) + INTERVAL '0 18:00:00' DAY TO SECOND
    --IF(SYSDATE BETWEEN TRUNC(SYSDATE) + to_dsinterval('0 16:00:00')
    --               AND TRUNC(SYSDATE) + to_dsinterval('0 18:00:00')
    )
    THEN
            dbms_output.put_line('now:'||sysdate); --now:01.03.2018 16:41:07
    end if;
end;
/

请考虑以下事项:

SQL

select interval '0 4'       day to hour  as ci from dual;          --+00 04:00:00.000000

select interval '0 4:10'    day to minute  as ci from dual;       --+00 04:10:00.000000

select interval '4:10'      hour to minute  as ci from dual;      --+00 04:10:00.000000

select interval '4:10:15'   hour to second  as ci from dual;      --+00 04:10:15.000000

select interval '0 4:10:15' day  to second as ci  from dual;       --+00 04:10:15.000000

PLSQL

declare

  --ci  CONSTANT INTERVAL DAY TO SECOND := interval '0 4'       day to  hour;      --PLS-00103

  --ci  CONSTANT INTERVAL DAY TO SECOND := interval '0 4:10'    day to  minute;    --PLS-00166

  --ci  CONSTANT INTERVAL DAY TO SECOND := interval '4:10'      hour to  minute;   --PLS-00166  

  --ci  CONSTANT INTERVAL DAY TO SECOND := interval '4:10:15'   hour to  second;   --PLS-00166  

  ci  CONSTANT INTERVAL DAY TO SECOND := interval '0 4:10:15' day to  second;    --[+00 04:10:15.000000] 

begin 
  dbms_output.put_line('['||ci||']'); 
end;
/
--PLS-00166:  bad format for  date, time, timestamp or interval literal
--PLS-00103:  Encountered the symbol "HOUR" when expecting  one of the  following: second