如果Year是有效年份,则需要Oracle SQL或存储过程将日期字段中的无效日期或月份转换为01。输入采用varchar
格式。
例如,如果输入值为20132016
(MMDDYYYY),则Year
为有效值2016
,现在我必须检查Day
和{{1} }。
在上面的示例中,Month
也有效Day
,但月份无效,值为13
。所以我必须将月份转换为01(默认值)。所以预期的输出是20
。
我需要在我的项目中预测某人的年龄,所以我没有为无效的出生日期插入Null,而是希望保留部分日期值,重要的是年份。
我有一个返回有效日期的函数,但是这个函数没有返回我想要的预期结果。
01132016
答案 0 :(得分:0)
嵌套测试是一种方式:
CREATE OR REPLACE FUNCTION func_chk_date (p_input IN VARCHAR2)
RETURN DATE
IS
v_date DATE := NULL;
BEGIN
v_date := TO_DATE (p_input, 'YYYY/MM/DD');
RETURN v_date;
EXCEPTION
WHEN OTHERS
THEN
BEGIN
v_date := TO_DATE (SUBSTR (p_input, 1, 4), 'YYYY');
RETURN v_date;
EXCEPTION
WHEN OTHERS
THEN
RETURN NULL;
END;
END func_chk_date;
答案 1 :(得分:0)
您可以创建一个功能来捕获您想要尝试更正的日期错误。以下只是一种方式。
create or replace function func_chk_date (date_string_in varchar2
,date_format_in varchar2 default 'mmddyyyy'
)
return date
is
bad_mon_e exception;
PRAGMA EXCEPTION_INIT(bad_mon_e, -01843);
bad_day_e exception;
PRAGMA EXCEPTION_INIT(bad_day_e, -01839);
bad_mon_day_e exception;
PRAGMA EXCEPTION_INIT(bad_mon_day_e, -01847);
date_value_l date;
function fix_dd
return varchar2
is
begin
return substr(date_string_in,1,2) || '01' || substr(date_string_in,5);
end fix_dd;
function fix_mm
return varchar2
is
begin
return '01' || substr(date_string_in,3);
end fix_mm;
begin
begin
date_value_l:= to_date( date_string_in, date_format_in);
exception
when bad_mon_e then
date_value_l:= func_chk_date (date_string_in => fix_mm
,date_format_in => date_format_in
);
when bad_day_e
or bad_mon_day_e then
date_value_l:=func_chk_date (date_string_in => fix_dd
,date_format_in => date_format_in
);
when others then
null; -- << Actually a very bad idea at least log the error >>
end ;
return date_value_l;
exception
when others then
dbms_output.put_line('Other Error:'|| sqlerrm);
end func_chk_date;
/
一些测试数据:
begin
dbms_output.put_line ('05052017 returned ' || func_chk_date('05052017'));
dbms_output.put_line ('02292017 returned ' || func_chk_date('02292017'));
dbms_output.put_line ('02292016 returned ' || func_chk_date('02292016'));
dbms_output.put_line ('13292016 returned ' || func_chk_date('13292016'));
dbms_output.put_line ('20402040 returned ' || func_chk_date('20402040'));
dbms_output.put_line ('0505yyyy returned ' || func_chk_date('0505yyyy'));
end ;
该功能按原样工作,但仅限于日期格式&#34; mmddyyyy&#34;。如果您需要不同的格式,则需要修改fix-mm和/或fix_dd函数。这也是一个递归例程,所以你需要保证有退出路径。
答案 2 :(得分:0)
你的第一个错误就在这里:
V_DATE := TO_DATE( P_INPUT, 'YYYY/MM/DD');
您说预期格式为'MMDDYYYY'
(例如&#39; 20132016&#39;)。那么为什么要尝试转换格式为'YYYY/MM/DD'
的字符串?
然后,当转换失败时,您甚至都没有尝试检测错误的部分并对其进行修复,而只是返回null。那么这怎么可能会返回所需的日期呢?
让我们从一个算法开始:
我在这里使用循环方便:
CREATE OR REPLACE FUNCTION func_chk_date (p_input IN VARCHAR2)
RETURN DATE
IS
v_date DATE;
v_datestring CHAR(8);
BEGIN
IF NOT REGEXP_LIKE(p_input, '^[[:digit:]]{8}$') THEN
RETURN NULL;
END IF;
v_datestring := p_input;
LOOP -- until conversion okay
BEGIN
v_date := TO_DATE(v_datestring, 'MMDDYYYY');
EXIT; -- conversion okay
EXCEPTION WHEN OTHERS THEN
IF SUBSTR(v_datestring, 5, 4) = '0000' THEN
v_datestring := SUBSTR(v_datestring, 1, 4) || '0001';
ELSIF TO_NUMBER(SUBSTR(v_datestring, 3, 2)) NOT BETWEEN 1 AND 12 THEN
v_datestring := SUBSTR(v_datestring, 1, 2) || '01' || SUBSTR(v_datestring, 5, 4);
ELSE
v_datestring := '01' || SUBSTR(v_datestring, 3, 6);
END IF;
END;
END LOOP;
RETURN V_DATE;
END FUNC_CHK_DATE;