ORA-01843: 不是一个有效的月份
Posted
技术标签:
【中文标题】ORA-01843: 不是一个有效的月份【英文标题】:ORA-01843: not a valid month When where condition is changed 【发布时间】:2014-08-19 11:04:59 【问题描述】:我遇到以下错误的问题
ORA-01843: 月份无效
如果我使用以下查询效果很好
SELECT mx.work_order_no, mx.work_order_name, mx.comments
FROM max_orders mx
WHERE TO_DATE (wo_dt, 'dd/mm/rr') <= (TO_DATE (SYSDATE, 'dd/mon/rr') - 7)
但是,如果我将 where 条件子句更改为
WHERE TO_DATE (wo_dt, 'dd/mm/rr') >= (TO_DATE (SYSDATE, 'dd/mon/rr') - 7)
我遇到了问题
ORA-01843: 月份无效
是什么原因造成的,我该如何解决这个错误?
更新 1
基础视图
SELECT work_order_no,
work_order_name,
wo_dt,
comments
FROM (SELECT mx_master.work_order_no,
mx_master.work_order_name,
SUBSTR (mx_master.uom, 1, 15) wo_dt,
mx_master.remarks
FROM mx_wo_data mx_master)
【问题讨论】:
由于>
>
的条件,您可能会得到一个不是有效日期的值
该条件在日期转换后应用。查看执行计划以查看条件更改是否仍在改变它会很有趣;但我怀疑可能还有其他未显示的过滤器。无论哪种方式,wt_dt
都是一个字符串,其值与您的模式不匹配;或者它是一个日期并且您的 NLS 设置与您使用的格式模型不匹配。可能数据有问题,是的 - 这就是为什么您不应该将日期存储为字符串。
TO_DATE (SYSDATE, 'dd/mon/rr')
没有任何意义。 to_date()
将 varchar
转换为 date
。 sysdate
已经是一个日期。 To call 首先将sysdate
转换为varchar
,然后将其转换回date
。
你能添加表的 DDL 和两个查询的执行计划吗?您能否澄清第一个查询是否完全按照所示工作 - 您从两个查询中删除了其他条件以进行测试?好吧,我说桌子……max_orders
是桌子,还是视图?如果是视图,请显示其定义以及基础表的结构。听起来仍然像 NLS 问题....
因此,根据视图定义,wo_dt
是一个字符串,而不是日期,并且其中的值不代表您正在使用的格式模型的有效日期。
【参考方案1】:
SYSDATE
已经是一个日期。您不应该将其传递给TO_DATE()
。当您这样做时,您正在对字符串进行隐式转换,然后进行显式转换。 Gordon Linoff 已经展示了一种更好的方法来做到这一点。
根据您添加的视图定义,wo_dt
是一个字符串。您期望它采用dd/mm/rr
格式。该错误告诉您该列中的值实际上不是该格式,因此您需要检查视图或基础表中的数据以查看哪些记录具有不正确的数据。
您可以使用something like this 排除格式不正确的值;或更有用地识别错误值,以便可以删除或纠正它们,例如类似于:
select * from max_orders
where my_to_date(wo_dt, 'dd/mm/rr') is null;
或来自基础表:
select * from mx_wo_data
where my_to_date(substr(uom, 1, 8), 'dd/mm/rr') is null;
如果您无法创建函数,那么您可以在匿名块中使用相同的逻辑。
奇怪的是,更改条件会导致错误,因为您的(隐式和显式)转换是在评估条件之前应用的,并且使用该函数意味着该列上的任何索引都不能使用;所以(在没有任何其他过滤器的情况下)您应该对两个查询进行全表扫描,转换应该在过滤之前应用于列中的所有值,并且您应该以任何一种方式得到错误。所以这并不能真正回答问题的那个方面。
【讨论】:
我尝试过使用WHERE wo_dt >= TRUNC(SYSDATE - 7)
,这也会导致ORA-01843: not a valid
错误。
max_orders
是一个视图,我已将其查询作为更新 1 包含在我的问题中。
不,如果wo_dt
值为空(因此uom
为空),则不会生成此(或任何)错误。您的值类似于 08/19/14
而不是 19/08/14
。
@Polppan - 你意识到我正在使用链接答案中的 Justin 的 my_to_date
函数,这与 ammoQ 的函数的想法相同,对吧?不是普通的to_date
?也许那个链接太微妙了。 ammoQ 当然也能胜任。
糟糕,我没有注意到你答案中的链接,否则我不会发布类似的功能:/【参考方案2】:
我建议你创建一个存储函数来识别坏行:
create function invalid_date(p_d in varchar2) return number as
v_d date;
begin
v_d := TO_DATE(p_d, 'dd/mm/rr');
return 0;
exception
when others then
return 1;
end;
/
select * from mx_orders where invalid_date(wo_dt)=1;
【讨论】:
太棒了,这确实有助于追踪错误的行,正如@Alex 正确指出的那样,mm/dd/rr
格式中有几行。赞赏。【参考方案3】:
不要将sysdate
转换为日期!只需使用:
WHERE TO_DATE(wo_dt, 'dd/mm/rr') >= trunc(SYSDATE - 7)
【讨论】:
我进行了此更改,但是当我滚动查看结果或在报告中使用此查询时,在对报告页面进行分页时,我确实收到了ORA-01843: not a valid
month 错误。你怀疑数据有问题吗?因为这个查询或报告长期以来一直没有任何错误。谢谢以上是关于ORA-01843: 不是一个有效的月份的主要内容,如果未能解决你的问题,请参考以下文章