如何转换日期忽略ORA-01847错误日期必须在1月和最后一天之间

时间:2018-02-12 10:36:11

标签: java sql oracle

我正在使用函数Exception in component tOracleInput_1 java.sql.SQLDataException: ORA-01847: le jour du mois doit être compris entre 1 et le dernier jour du mois ORA-01847: "day of month must be between 1 and last day of month"

执行我的SQL请求时,我遇到了这些错误:

Context.getDatabasePath

有没有办法忽略这些错误并按日期计算,即使月份的日期较大,那么该月份是否有效?

4 个答案:

答案 0 :(得分:4)

升级到Oracle 12.2并使用to_datedefault on conversion error子句:

to_date(datecolumn default null on conversion error, 'yyyymmdd')

(您可能需要将其嵌套在coalescecase表达式中,以便在日期因转换错误而出现null时重新尝试转换。)

或者,编写您自己的PL / SQL函数,该函数接受字符串和格式,例如to_date(),但还有其他步骤来处理无效数据,并使用它来代替to_date()。 (如果在12.1或更高版本中,请将其设为pragma udf)。

create or replace function to_date_safe(p_datestr varchar2) return date
as
    l_result date;

    invalid_day_for_month exception;
    pragma exception_init(invalid_day_for_month, -1847);
    pragma udf;
begin
    begin
        l_result := to_date(p_datestr,'YYYYMMDD');
    exception
        when invalid_day_for_month then
            l_result := last_day(to_date(substr(p_datestr,1,6),'YYYYMM'));
    end;

    return l_result;
end to_date_safe;

(编辑)从Oracle 12.1开始,您可以使用SQL查询定义PL / SQL函数。

create table demo (datecolumn varchar2(8));

insert all
    into demo (datecolumn) values ('20180101')
    into demo (datecolumn) values ('20180399')
    into demo (datecolumn) values ('20180299')
select * from dual;

with function to_date_safe(p_datestr varchar2) return date
     as
         invalid_day_for_month exception;
         pragma exception_init(invalid_day_for_month, -1847);
         l_result date;
     begin
         begin
             l_result := to_date(p_datestr,'YYYYMMDD');
         exception
             when invalid_day_for_month then
                 l_result := last_day(to_date(substr(p_datestr,1,6),'YYYYMM'));
         end;

         return l_result;
     end;
select datecolumn
     , to_date_safe(datecolumn) as converted_date
from   demo
/

DATECOLUMN CONVERTED_DATE
---------- -------------
20180101   01-JAN-2018
20180399   31-MAR-2018
20180299   28-FEB-2018

3 rows selected.

或者,用Java进行转换。

答案 1 :(得分:2)

你可以(正如@William所提到的)编写一个函数,尝试使用您期望的格式模型将字符串转换为日期,然后处理您希望看到的任何特定错误。对于您的示例问题,如果您希望将无效的日期数视为该月的最后一天,则可以执行以下操作:

create or replace function updateDate(p_date varchar2) return date as
  l_date date;
  e_bad_day exception;
  pragma exception_init (e_bad_day, -1847);
begin
  begin
    -- try to convert
    l_date := to_date(p_date,'yyyymmdd');
  exception
    when e_bad_day then
      -- ignore the supplied day value and get last day of month
      l_date := last_day(to_date(substr(p_date, 1, 6), 'yyyymm'));
  end;
  return l_date;
end;
/

第一个to_date()位于嵌套块中。如果它获得特定的异常-1847,那么异常处理程序会尝试仅使用字符串的前六个字符来表示日期 - 这将为您提供该月的第一天 - 然后使用last_day()函数为您提供好吧,那个月的最后一天。

快速演示通过CTE提供一些样本值:

alter session set nls_date_format = 'YYYY-MM-DD';

with t (dt) as (
            select '20180218' from dual
  union all select '20160299' from dual
  union all select '20180299' from dual
  union all select '20160435' from dual
)
select dt, updateDate(dt)
from t;

DT       UPDATEDATE
-------- ----------
20180218 2018-02-18
20160299 2016-02-29
20180299 2018-02-28
20160435 2016-04-30

它不会处理任何其他错误,无论是从第一次转换尝试还是从第二次转换尝试,如果还有其他错误。根据您的数据有多糟糕,您可能需要以类似的方式处理其他方案。

由于您无法知道原始日期应该是什么,仅仅输入的内容无效,将日期完全抛弃并将其视为空而不是最后一天可能更安全。这个月,但这取决于你想要/需要如何处理坏的价值。

如前所述,您不应该首先将日期存储为字符串 - 如果数据类型正确,则不会出现这些类型的问题。无效的值会被捕获,并且可能已被用户在此时更正,而不是您必须尝试猜测它们的含义。

答案 2 :(得分:1)

只需检查日期格式如何存储在数据库中,并相应地更改格式。

例如:to_date(start_time,' dd-Mon-YYYY')

答案 3 :(得分:0)

选择start_time,例如substr('2016-04-35',9,2)> to_char(last_day(to_date(substr('2016-04-35',6,2)|| substr('2016-04-35',1,4),'mmyyyy')),'dd')然后 to_date(substr('2016-04-35',9,2) - (substr('2016-04-35',9,2)-to_char(last_day(to_date(substr('2016-04-35',6) ,2)|| substr('2016-04-35',1,4),'mmyyyy')),'dd')) || substr('2016-04-35',6,2)|| substr('2016-04-35',1,4),'ddmmyyyy') 其他 TO_DATE(START_TIME) 从table_name结束;