ORA-01839“日期对于指定的月份无效”对于 where 子句中的 to_date

Posted

技术标签:

【中文标题】ORA-01839“日期对于指定的月份无效”对于 where 子句中的 to_date【英文标题】:ORA-01839 "date not valid for month specified" for to_date in where clause 【发布时间】:2016-02-08 12:53:26 【问题描述】:

我有以下查询 (BOCRTNTIME - varchar e.g 2015-02-28 12:21:45, VIEW_BASE_MARIX_T - some view):

select BOCRTNTIME
    from VIEW_BASE_MARIX_T
    where to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD')
        between (to_date ('2016-01-01', 'YYYY-MM-DD'))
            and (to_date ('2016-02-01', 'YYYY-MM-DD'))

执行时出现错误:

ORA-01839:  "date not valid for month specified"

我认为BOCRTNTIME中可能有不正确的数据,所以执行以下查询:

select distinct
         substr(BOCRTNTIME,1,8),
         substr(BOCRTNTIME,9,2)
  from VIEW_BASE_MARIX_T
 order by substr(BOCRTNTIME,9,2);

但一切看起来都很好:http://pastebin.com/fNjP4UAu。 以下查询也执行没有任何错误:

select to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') 
  from VIEW_BASE_MARIX_T;

我已经尝试将trunc() 添加到所有to_date() 但没有运气。我还创建了 pl/sql 过程,该过程采用VIEW_BASE_MARIX_T 的一项一项形式并将其转换为日期 - 一切正常。 任何想法为什么我在第一次查询时出错?

UPD:在视图中使用的表查询工作正常,但在视图中 - 不是

UPD2:我们几乎没有相同产品的环境,但只有一个出现错误

UPD3:问题已通过在视图中使用的表中搜索无效日期解决

【问题讨论】:

这个select substr(BOCRTNTIME,1,10)的选择是"2015-07-"?如果是,那么如果您的错误就是问题所在。它应该包含一个正常工作的天值,例如“2015-07-01”。 BOCRTNTIME 的值是多少? 您可以发布链接的结果吗?它被我屏蔽了。 当您尝试select to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') from VIEW_BASE_MARIX_T; 时,您确定选择了所有行吗?像 SQL-Developer 这样的一些工具只会显示例如50 个结果;该错误可能会在稍后的结果中出现。 生成视图的 DDL 语句是什么? @MT0 有视图:pastebin.com/UntX5FfV 和视图中使用的表:pastebin.com/PcFppgAg 【参考方案1】:

评论有点太长了 - 创建一个简单的函数来测试日期:

CREATE FUNCTION is_Valid_Date(
  in_string VARCHAR2,
  in_format VARCHAR2 DEFAULT 'YYYY-MM-DD'
) RETURN NUMBER DETERMINISTIC
AS
  dt DATE;
BEGIN
  dt := TO_DATE( in_string, in_format );
  RETURN 1;
EXCEPTION
  WHEN OTHERS THEN
    RETURN 0;
END;
/

那么你可以这样做:

SELECT BOCRTNTIME
FROM   VIEW_BASE_MARIX_T
WHERE  is_Valid_Date( substr(BOCRTNTIME,1,10) ) = 0;

您可能会发现 4 月、6 月、9 月或 11 月有该月 31 日的条目,或者 2 月的值大于 28/29 日(尽管我在您粘贴的数据中看不到类似的内容)。

否则您可以尝试使用 ANSI 日期文字:

SELECT BOCRTNTIME
FROM   VIEW_BASE_MARIX_T
WHERE  to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') between DATE '2016-01-01' and DATE '2016-02-01';

或者,甚至更简单,给定输入的格式:

SELECT BOCRTNTIME
FROM   VIEW_BASE_MARIX_T
WHERE  substr(BOCRTNTIME,1,10) between '2016-01-01' and '2016-02-01';

【讨论】:

第一个查询(带函数)什么都不返回,第二个 - ORA-01839,第三个呢 - 我不认为将日期比较为 varchar - 好主意 您将日期存储为 ISO8601 格式(或足够接近) - 使用字符串比较来测试 valid 日期是否在使用日期范围内没有问题这种格式。这是设计格式的原因之一。 谢谢,使用@Ricardo Arnold 的函数和想法来针对表运行它,但没有查看我发现错误日期记录【参考方案2】:

我认为可能发生的事情是 Oracle 正在将谓词推送到视图的基础表。

您是否尝试过运行查询

select to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') BOCRTNTIME
from MY_TABLE

而不是查询视图?

您也可以使用 NO_PUSH_PRED 提示确认这一点

select /*+ NO_PUSH_PRED(VIEW_BASE_MARIX_T) */
BOCRTNTIME
from VIEW_BASE_MARIX_T
where 
to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') between (to_date ('2016-01-01', 'YYYY-MM-DD')) and (to_date ('2016-02-01', 'YYYY-MM-DD'))

【讨论】:

@Moudiz:你什么意思? 查询表而不是视图,工作正常,但在视图上使用 NO_PUSH_PRED 提示仍然失败 @DmitryKompot 你能提供构建表格和视图的脚本并插入脚本吗? 我没有插入脚本,但有视图:pastebin.com/UntX5FfV 和视图中使用的表:pastebin.com/PcFppgAg 当您执行以下操作时会发生什么:create table my_tab_test as select * from VIEW_BASE_MARIX_T 然后在新创建的表上运行相同的查询? select BOCRTNTIME from MY_TAB_TEST where to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') between (to_date ('2016-01-01', 'YYYY-MM-DD')) and (to_date ('2016-02-01', 'YYYY-MM-DD'))【参考方案3】:

错误消息表明您的月份中有一个无效的日期。用这个检查你的数据:

-- Check for months with 30 days
select substr(BOCRTNTIME,9,2), substr(BOCRTNTIME,6,2) from VIEW_BASE_MARIX_T where to_number(substr(BOCRTNTIME,6,2)) in (4,6,9,11) and to_number(substr(BOCRTNTIME,9,2))>30;

-- Check for february
select substr(BOCRTNTIME,9,2), substr(BOCRTNTIME,6,2) from VIEW_BASE_MARIX_T where to_number(substr(BOCRTNTIME,6,2))=2 and to_number(substr(BOCRTNTIME,9,2))>28;

【讨论】:

你可以从我的 pastebin 链接中看到没有这样的项目【参考方案4】:

这可能是一个很长的镜头,但between 的语法中没有括号,你试过删除它们吗?

select
    BOCRTNTIME
    from VIEW_BASE_MARIX_T
    where 
    to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') between to_date ('2016-01-01', 'YYYY-MM-DD') and to_date ('2016-02-01', 'YYYY-MM-DD')

【讨论】:

如果这是错误的原因,我会感到非常惊讶。 不,即使where to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') = to_date ('2015-06-01', 'YYYY-MM-DD') 也不起作用 好吧,在 oracle 只考虑整个括号作为 between 子句下限的参数的情况下值得尝试。

以上是关于ORA-01839“日期对于指定的月份无效”对于 where 子句中的 to_date的主要内容,如果未能解决你的问题,请参考以下文章

Oracle 服务器中的日期构造“Oracle 数据库错误 1839”

为啥我会收到“元素类型无效:需要字符串(对于内置组件)或类/函数(对于复合组件)......”?

对于独立应用程序(对于 Spring JMS),Java main 方法应该是啥?

对于软件工程的期望

为啥会提示“我们计算的请求签名与您提供的签名不匹配”。对于 GET 但不是 PUT 对于 OpenSearch?

对于Passenger,控制台日志(从puts的输出)去哪里......对于Nodejs