ORA-01722: 尝试在接下来 30 秒内获取预定信号的 Oracle 查询中的无效数字
Posted
技术标签:
【中文标题】ORA-01722: 尝试在接下来 30 秒内获取预定信号的 Oracle 查询中的无效数字【英文标题】:ORA-01722: invalid number in an Oracle query that tries to pick up the scheduled signals in the next 30 seconds 【发布时间】:2013-09-05 09:19:12 【问题描述】:我在 Oracle 11G 中有一个所谓的 signal_table,其中包含以下列:
signal_type VarChar(2) signal_time VarChar(2)
signal_time 的格式为 HH24:MI:SS(例如“15:35:30”),这意味着应用程序会在每天 15:35:30 触发此类信号。
现在,我正在尝试编写一个查询,列出所有将在 30 秒后触发的信号。
我尝试了类似的东西
select
signal_type,
signal_time,
from
signal_table
where
to_number(to_char(substr(signal_time,1,2)))*3600 + to_number(to_char(substr(signal_time,4,2)))*60 + to_number(to_char(substr(signal_time,7,2))) - to_number(to_char(sysdate,'HH24'))*3600 + to_number(to_char(sysdate,'MI'))*60 + to_number(to_char(sysdate,'SS')) < 30
;
认为我会在几秒钟内将 VarChar 时间戳转换为数字。 但是,对于上述查询,我收到“ORA-01722:无效号码”错误。
下面的查询可以正常工作:
select
signal_type,
signal_time,
to_number(to_char( substr(signal_time,1,2)))*3600 + to_number(to_char(substr(signal_time,4,2)))*60 + to_number(to_char(substr(signal_time,7,2))) - to_number(to_char(sysdate,'HH24'))*3600 + to_number(to_char(sysdate,'MI'))*60 + to_number(to_char(sysdate,'SS'))
from
signal_table
;
当我将 to_number 转换部分放在 where 子句中时,任何人都可以解释为什么会出现上述错误吗?
更好的是,有没有更优雅的方式来实现这个目标?
【问题讨论】:
1.您无法将 15:35:30 存储在给定的数据类型 varchar(2) 中。 2.您的第一个选择查询似乎没有任何错误。 3.您的选择查询有额外的逗号错误 你的逻辑会在 00:00:15 的信号时间工作吗? 【参考方案1】:只要表中的所有数据确实具有nn:nn:nn
格式的值,您所做的工作(在一定程度上)。该错误表明您至少有一行格式不正确。虽然奇怪的是您的第二个查询有效 - 也许您有一个未显示的 where
子句?
这是SQL Fiddle showing it action。它没有错误,但它显示了今天已经过去的所有信号时间,所以如果我理解你的话,你需要将它限制在当前时间和现在的 30 秒之间。 This fiddle 做到了这一点,并且还删除了一些不必要的转换:
select
signal_type,
signal_time
from
signal_table
where
(to_number(substr(signal_time,1,2))*3600
+ to_number(substr(signal_time,4,2))*60
+ to_number(substr(signal_time,7,2)))
- (to_number(to_char(sysdate,'HH24'))*3600
+ to_number(to_char(sysdate,'MI'))*60
+ to_number(to_char(sysdate,'SS'))) >= 0
and
(to_number(substr(signal_time,1,2))*3600
+ to_number(substr(signal_time,4,2))*60
+ to_number(substr(signal_time,7,2)))
- (to_number(to_char(sysdate,'HH24'))*3600
+ to_number(to_char(sysdate,'MI'))*60
+ to_number(to_char(sysdate,'SS'))) < 30
;
您还可以将signal_time
转换为日期并将其与 sysdate 进行比较:
select
signal_type,
signal_time
from
signal_table
where
to_date(signal_time, 'HH24:MI:SS') - trunc(sysdate, 'MM')
>= sysdate - trunc(sysdate, 'DD')
and to_date(signal_time, 'HH24:MI:SS') - trunc(sysdate, 'MM')
< sysdate + interval '30' second - trunc(sysdate, 'DD')
;
Yet another fiddle。这会将时间部分提取为一天的一小部分,对于 signal_time
,当前时间和当前时间 + 30 秒。
要查找格式不正确的值,快速检查如下:
select
signal_type,
signal_time
from
signal_table
where
not regexp_like(signal_time, '^\d\d:\d\d:\d\d$')
;
(我对正则表达式不太感兴趣,因此可能可以做得更整洁)。但这只会发现格式错误的值,并且不会发现无效时间,例如24:60:60
,您的查询将转换它。日期版本会抱怨这一点(ORA-01850),但也会更宽容略有不同的格式,例如缺少一个元素的前导零。这可能是一件好事,也可能不是一件好事。
如果您有不同格式的记录需要排除但无法更正,那么(除了建议数据模型问题)您可以将检查查询用作主查询中的子查询:
select
signal_type,
signal_time
from
(
select
*
from
signal_table
where
regexp_like(signal_time, '^\d\d:\d\d:\d\d$')
)
where
to_date(signal_time, 'HH24:MI:SS') - trunc(sysdate, 'MM')
> sysdate - trunc(sysdate, 'DD')
and to_date(signal_time, 'HH24:MI:SS') - trunc(sysdate, 'MM')
< sysdate + interval '30' second - trunc(sysdate, 'DD')
;
Another fiddle 显示此工作,然后较早的更简单的查询失败,使用相同的数据 - 包括一条错误记录。
如果您的格式有效但时间无效(例如24:60:60
),它仍然会失败。如果是这种情况,那么您确实需要清理数据,但可能会提出更严格的正则表达式,或者使用函数 something like this 在运行时检查有效格式。
在某些情况下,您可能需要添加提示以停止将过滤器应用于内部选择,但我认为在这种情况下这不会成为问题。
【讨论】:
感谢亚历克斯的回复。实际上,真正的罪魁祸首可能是不合格的记录。在我编写此查询的真实表中,有 2 条记录,其中 signal_time 值的格式不同。我试过这个 select signal_type, signal_time from signal_table where to_date(signal_time, 'HH24:MI:SS') - trunc(sysdate, 'MM') >= sysdate - trunc(sysdate, 'DD') and to_date(signal_time, 'HH24 :MI:SS') - trunc(sysdate, 'MM') 我也尝试了类似下面的 pure_signal as( select signal_type, signal_time from signal_table where signal_type != 'AAA' and signal_type != 'BBB' ) select * from pure_signal where to_date(signal_time, 'HH24 :MI:SS') - trunc(sysdate, 'MM') >= sysdate - trunc(sysdate, 'DD') and to_date(signal_time, 'HH24:MI:SS') - trunc(sysdate, 'MM') 对于上面的查询,我得到“ORA-01830:日期格式图片在转换整个输入字符串之前结束”不幸的是,我没有权限在生产中创建临时表... 抱歉,这些 cmets 看起来很混乱...我希望我能以与原始帖子相同的方式对其进行格式化... @akisoni - 这两条记录是否合法地具有不同的格式(肯定不是?),还是可以修复?他们的数据是否必须包含在查询中,如果是,它们是什么格式?【参考方案2】:SELECT
TO_CHAR(TO_DATE(signal_time, 'HH24:MI:SS'), 'HH24:MI:SS') - TO_CHAR(NOW(), 'HH24:MI:SS')
;
【讨论】:
Oracle 中没有now()
函数。
now()
不是 Oracle 函数,您需要使用 sysdate
。更重要的是,从另一个字符串中减去一个字符串会给您带来什么? Oracle 会再次抱怨 ORA-01722,因为它会尝试将两个字符串隐式转换为数字,这会失败。
感谢您的建议。我实际上也尝试将 signal_time 转换为日期格式,但得到“ORA-01830:日期格式图片在转换整个输入字符串之前结束”。当我作为 cmets 发布到 Alex 的另一个答案线程时,这可能是由于表中实际上有一些不符合格式的记录。到目前为止,我一直无法解决这个问题......以上是关于ORA-01722: 尝试在接下来 30 秒内获取预定信号的 Oracle 查询中的无效数字的主要内容,如果未能解决你的问题,请参考以下文章
ORA-01722: 无效编号 当我尝试执行存储过程时。甲骨文错误
仅在案例语句中添加年份得到无效数字错误 - ORA-01722