Ady*_*can 3 oracle format date
我想将包含日期的字符串带入单一格式的日期。例如:
我试图删除所有特殊字符,然后使用函数将该字符串转换为单一日期格式。我的函数返回了更多异常,我不知道为什么...
功能:
CREATE OR REPLACE FUNCTION normalize_date (data_in IN VARCHAR2)
RETURN DATE
IS
tmp_month VARCHAR2 (3);
tmp_day VARCHAR2 (2);
tmp_year VARCHAR2 (4);
TMP_YEAR_NUMBER NUMBER;
result DATE;
BEGIN
tmp_day := SUBSTR (data_in, 1, 2);
tmp_year := SUBSTR (data_in, -4);
--if(REGEXP_LIKE(SUBSTR(data_in,3,2), '[:alpha:]')) then
if(SUBSTR(data_in,3,1) in ('a','j','i','f','m','s','o','n','d','A','J','I','F','M','S','O','N','D')) then
tmp_month := UPPER(SUBSTR (data_in, 3, 3));
else
tmp_month := SUBSTR (data_in, 3, 2);
end if;
DBMS_OUTPUT.put_line (tmp_year);
TMP_YEAR_NUMBER := TO_NUMBER (tmp_year);
IF (tmp_month = 'JAN')
THEN
tmp_month := '01';
END IF;
IF (tmp_month = 'FEB')
THEN
tmp_month := '02';
END IF;
IF (tmp_month = 'MAR')
THEN
tmp_month := '03';
END IF;
IF (tmp_month = 'APR')
THEN
tmp_month := '04';
END IF;
IF (tmp_month = 'MAY')
THEN
tmp_month := '05';
END IF;
IF (tmp_month = 'JUN')
THEN
tmp_month := '06';
END IF;
IF (tmp_month = 'JUL')
THEN
tmp_month := '07';
END IF;
IF (tmp_month = 'AUG')
THEN
tmp_month := '08';
END IF;
IF (tmp_month = 'SEP')
THEN
tmp_month := '09';
END IF;
IF (tmp_month = 'OCT')
THEN
tmp_month := '10';
END IF;
IF (tmp_month = 'NOV')
THEN
tmp_month := '11';
END IF;
IF (tmp_month = 'DEC')
THEN
tmp_month := '12';
END IF;
-- dbms_output.put_line(tmp_day || '~'||tmp_year || '~' ||tmp_month);
IF (LENGTH (tmp_day || tmp_year || tmp_month) <> 8)
THEN
result := TO_DATE ('31122999', 'DDMMYYYY');
RETURN result;
END IF;
-- dbms_output.put_line('before end');
result:=TO_DATE (tmp_day || tmp_month ||tmp_year , 'DDMMYYYY');
-- dbms_output.put_line('date result: '|| result);
RETURN result;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
NULL;
WHEN OTHERS
THEN
result := TO_DATE ('3012299', 'DDMMYYYY');
RETURN result;
RAISE;
END normalize_date;
Run Code Online (Sandbox Code Playgroud)
用法
SELECT customer_no,
str_data_expirare,
normalize_date (str_data_expirare_trim) AS data_expirare_buletin
FROM (SELECT customer_no,
str_data_expirare,
REGEXP_REPLACE (str_data_expirare, '[^a-zA-Z0-9]+', '')
AS str_data_expirare_trim
FROM (SELECT Q1.set_act_id_1,
Q1.customer_no,
NVL (SUBSTR (set_act_id_1,
INSTR (set_act_id_1,
'+',
1,
5)
+ 1,
LENGTH (set_act_id_1)),
'NULL')
AS str_data_expirare
FROM STAGE_CORE.IFLEX_CUSTOMERS Q1
WHERE Q1.set_act_id_1 IS NOT NULL
)
);
Run Code Online (Sandbox Code Playgroud)
如果您对所有可能的日期格式都有很好的了解,则使用蛮力可能会更容易:
create or replace function clean_date
( p_date_str in varchar2)
return date
is
l_dt_fmt_nt sys.dbms_debug_vc2coll := sys.dbms_debug_vc2coll
('DD-MON-YYYY', 'DD-MON-YY', 'DD-MM-YYYY', 'MM-DD-YYYY', 'YYYY-MM-DD'
, 'DD/MM/YYYY', 'MM/DD/YYYY', 'YYYY/MM/DD', 'DD/MM/YY', 'MM/DD/YY');
return_value date;
begin
for idx in l_dt_fmt_nt.first()..l_dt_fmt_nt.last()
loop
begin
return_value := to_date(p_date_str, l_dt_fmt_nt(idx));
exit;
exception
when others then null;
end;
end loop;
if return_value is null then
raise no_data_found;
end if;
return return_value;
exception
when no_data_found then
raise_application_error(-20000, p_date_str|| ' is unknown date format');
end clean_date;
/
Run Code Online (Sandbox Code Playgroud)
请注意,Oracle的现代版本在日期转换方面相当宽容。此函数以列表中未列出的格式处理日期,从而产生一些有趣的结果:
SQL> select clean_date('20160817') from dual;
CLEAN_DAT
---------
17-AUG-16
SQL> select clean_date('160817') from dual;
CLEAN_DAT
---------
16-AUG-17
SQL>
Run Code Online (Sandbox Code Playgroud)
面对松散的数据完整性规则,这证明了自动数据清理的局限性。犯罪的工资是损坏的数据。
@AlexPoole提出了使用'RR'格式的问题。日期掩码的此元素是作为Y2K合并引入的。令人沮丧的是,我们距新千年已经过去了将近二十年。
无论如何,问题是这样的。如果我们将此字符串'161225'转换为日期,它具有什么世纪?好吧,'yymmdd'会给2016-12-15。足够公平,但是呢'991225'?我们真正想要的日期是2099-12-15多少?这是 'RR'格式发挥作用的地方。基本上,它默认世纪:数字00-49默认为20,50-99默认为19。该窗口由Y2K问题确定:在2000年,'98提及近期的可能性大于近期的可能性,并且类似的逻辑适用于'02。因此是1950年的中点。请注意,这是一个固定点,而不是滑动窗口。随着我们距2000年的发展越来越远,该枢轴点变得越没有用处。了解更多。
不管怎样,关键的一点是,“RRRR”不与其他日期格式发挥很好:to_date('501212', 'rrrrmmdd') hurlsORA-01843:不是有效的月份. So, use“RR” and test for it before using“YYYY'`。所以我修改过的函数(经过整理)如下所示:
create or replace function clean_date
( p_date_str in varchar2)
return date
is
l_dt_fmt_nt sys.dbms_debug_vc2coll := sys.dbms_debug_vc2coll
('DD-MM-RR', 'MM-DD-RR', 'RR-MM-DD', 'RR-DD-MM'
, 'DD-MM-YYYY', 'MM-DD-YYYY', 'YYYY-MM-DD', 'YYYY-DD-MM');
return_value date;
begin
for idx in l_dt_fmt_nt.first()..l_dt_fmt_nt.last()
loop
begin
return_value := to_date(p_date_str, l_dt_fmt_nt(idx));
exit;
exception
when others then null;
end;
end loop;
if return_value is null then
raise no_data_found;
end if;
return return_value;
exception
when no_data_found then
raise_application_error(-20000, p_date_str|| ' is unknown date format');
end clean_date;
/
Run Code Online (Sandbox Code Playgroud)
关键点仍然是:在解释日期时,我们使此功能的智能程度是有限的,因此请确保您以最合适的方式进行领导。如果您认为大多数日期字符串都适合日-月-年,则将其放在第一位;您仍然会得到一些错误的演员表,但是如果您以年-月-日为首的话,您会得到更少的帮助。