Sql ORA-01839“;指定月份的日期无效";对于where条款中的截止日期

Sql ORA-01839“;指定月份的日期无效";对于where条款中的截止日期,sql,oracle,date-format,to-date,Sql,Oracle,Date Format,To Date,我有以下查询(bocrntime-varchar,例如2015-02-28 12:21:45,VIEW\u BASE\u MARIX\u T-some VIEW): 执行时,我得到一个错误: ORA-01839: "date not valid for month specified" 我认为bocrntime中可能有不正确的数据,所以执行以下查询: select distinct substr(BOCRTNTIME,1,8), substr(BOCRTN

我有以下查询(
bocrntime-varchar,例如2015-02-28 12:21:45,VIEW\u BASE\u MARIX\u T-some VIEW
):

执行时,我得到一个错误:

ORA-01839:  "date not valid for month specified"
我认为
bocrntime
中可能有不正确的数据,所以执行以下查询:

select distinct
         substr(BOCRTNTIME,1,8),
         substr(BOCRTNTIME,9,2)
  from VIEW_BASE_MARIX_T
 order by substr(BOCRTNTIME,9,2);
但一切看起来都很好。 此外,执行以下查询时不会出现任何错误:

select to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') 
  from VIEW_BASE_MARIX_T;
我已经尝试将
trunc()
添加到所有
to\u date()
,但没有成功。此外,我还创建了pl/sql过程,该过程采用逐项形式
VIEW\u BASE\u MARIX\u T
,并将其转换为日期,一切正常。 知道我第一次查询时出错的原因吗

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

UPD2:我们几乎没有使用相同产品的环境,但只在一个环境中出错


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

这可能需要很长时间,但其语法中没有括号,您是否尝试删除它们

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')

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

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';

我认为可能发生的情况是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'))

错误消息表示您的月份中有一个无效的日期。用以下内容检查您的数据:

-- 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;

select substr(bocrntime,1,10)
的选择是
“2015-07-”
?如果是的话,那就是你的错误。它应该包含“正常工作”的日值,例如“2015-07-01”。BOCRNTIME的价值是什么?你能发布你链接的结果吗?它对我来说是被阻止的。当你尝试
从视图中选择日期(substr(bocrntime,1,10),'YYYY-MM-DD')是否确保选择了所有行?一些工具,如SQL Developer,只显示50个结果;错误可能会在稍后出现。生成视图的DDL语句是什么?@MT0有view:pastebin.com/UntX5FfV和view:pastebin.com/PcFppgAgI中使用的表如果这是错误的原因,我会感到非常惊讶。不,甚至
到哪里日期(substr(bocrntime,1,10),'yyyyy-MM-DD')=到日期('2015-06-01','yyyyy-MM-DD'))
效果不好,值得一试,因为oracle只考虑将整个括号作为between子句中下限的参数。@Moudiz:什么意思?在表上查询,而不是在视图上查询,效果很好,但是在视图中仍然没有PUSH PRED提示fails@DmitryKompot您可以提供用于构建表和视图的脚本以及插入脚本吗?我没有插入脚本,但是有视图:和视图中使用的表:当您执行以下操作时会发生什么:
创建表my\u tab\u test作为select*from view\u BASE\u MARIX\T
,然后在新创建的表上运行相同的查询<代码>从“我的”选项卡中选择“我的”选项卡中的“我的”选项卡中的“我的”选项卡中的“我的”选项卡中选择“我的”选项卡中的“我的”选项卡中的“我的”选项卡中的“我的”选项卡中的“我的”选项卡中的“我的”选项卡中的“我的”选项卡中的“我的”选项卡中的“我的”选项卡中的“我的”选项卡中的“我的”选项卡中的“我的”选项卡中的日期(substr(bocrt,1,10),“yyyyyyy-MM-DD”)介于(到日期(”,第三个呢?我不认为将日期作为varchar进行比较-很好的主意您将日期存储为ISO8601格式(或足够接近格式)-使用字符串比较来测试有效日期是否在使用此格式的日期范围内没有问题。这就是设计该格式的原因之一。谢谢,使用@Ricardo Arnold的函数和想法,对表运行它,但不查看。我找到了errorneus日期记录。您可以从我的pastebin链接中看到,没有此类项目
-- 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;