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
我正在尝试检查我当前的时间戳是否介于两个时间戳之间。
我在我的 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