[英]ORA-01847 day of month must be between 1 and last day of month - Inserting date into Oracle Database
[英]How to convert date ignoring ORA-01847 error day of month must be between 1 and last day of month
我正在使用函数TO_DATE(datecolumn,'yyyymmdd' ) as DATE_REAL
执行我的SQL请求时,出现以下错误:
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"
是否可以忽略这些错误并按原样使用日期,即使月份中的日期大于该日期也适用于该月份?
升级到Oracle 12.2,并使用to_date
的default on conversion error
子句:
to_date(datecolumn default null on conversion error, 'yyyymmdd')
(您可能需要将其嵌套在coalesce
或case
表达式中,以在由于转换错误而导致日期为空时重新尝试转换。)
或者,编写自己的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进行转换。
您可以(如@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
它不会处理任何其他错误,无论是第一次转换还是第二次转换(如果仍然有其他错误)。 根据数据的严重程度,您可能需要以类似方式处理其他情况。
由于您无法知道原始日期应该是什么,因此仅输入的内容是无效的,因此将日期完全丢弃并将其视为空值(而不是月的最后一天)可能更安全,但这取决于您希望/需要如何使用不良值。
就像已经提到的那样,您首先不应该将日期存储为字符串-如果数据类型正确,则不会出现这些类型的问题。 那时,无效值已经被用户捕获并且可以被用户纠正,而您不必尝试猜测它们可能意味着什么。
只需检查日期格式在数据库中的存储方式,并相应地更改格式即可。
例如:to_date(start_time,'dd-Mon-YYYY')
选择开始时间,当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结束;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.