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

时间:2016-02-08 12:53:26

标签: sql oracle date-format to-date

我有以下查询(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:问题已通过视图

中使用的表中的搜索无效日期解决

4 个答案:

答案 0 :(得分:4)

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

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 Date文字:

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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

using (OracleDataReader dr =  Zurich.Common.OracleDataAccess.ExecuteReader(cn, CommandType.Text, mySQL))
        {
            if (dr.HasRows) // file exists in DB
            {
                while (dr.Read())
                {
                    currentDays = Convert.ToInt16(((DateTime.Now.AddDays(-1).Date) - Convert.ToDateTime(dr[0])).TotalDays);
                    Console.WriteLine(CheckDate(Convert.ToDateTime(dr[0])));

                    lbBugs.Items.Add(String.Format("{0:dd/M/yyyy H:mm:ss}", dr[0]) + ": " + dr.GetString(1) + " : " + currentDays);

答案 3 :(得分:0)

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

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