Nếu bạn có ý tưởng tốt về tất cả các định dạng ngày tháng có thể có, thì việc sử dụng brute force có thể dễ dàng hơn:
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;
/
Cần biết rằng các phiên bản hiện đại của Oracle khá dễ dàng với việc chuyển đổi ngày tháng. Hàm này xử lý ngày tháng ở các định dạng không có trong danh sách, với một số hậu quả thú vị:
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>
Điều này chứng tỏ giới hạn của việc làm sạch dữ liệu tự động khi đối mặt với các quy tắc toàn vẹn dữ liệu lỏng lẻo. Tiền công của tội lỗi là dữ liệu bị hỏng.
@AlexPoole đặt ra vấn đề sử dụng 'RR'
định dạng. Yếu tố này của mặt nạ ngày tháng được giới thiệu dưới dạng k bùn Y2K. Thật đáng buồn khi chúng ta vẫn đang thảo luận về nó trong gần hai thập kỷ về Thiên niên kỷ mới.
Dù sao, vấn đề là thế này. Nếu chúng ta truyền chuỗi này '161225'
đến nay nó có từ thế kỷ nào? Chà, 'yymmdd'
sẽ cung cấp cho 2016-12-15
. Khá ổn, nhưng '991225'
thì sao ? Khả năng ngày chúng ta thực sự muốn là 2099-12-15
như thế nào ? Đây là nơi chứa 'RR'
định dạng phát huy tác dụng. Về cơ bản, nó mặc định thế kỷ:số 00-49 mặc định là 20, 50-99 mặc định là 19. Cửa sổ này được xác định bởi sự cố Y2K:vào năm 2000, nhiều khả năng là '98
đề cập đến quá khứ gần đây hơn là tương lai gần và logic tương tự được áp dụng cho '02
. Do đó là nửa điểm của năm 1950. Lưu ý rằng đây là điểm cố định không phải là cửa sổ trượt. Khi chúng ta tiến xa hơn từ năm 2000, điểm xoay đó càng trở nên ít hữu ích hơn. Tìm hiểu thêm.
Dù sao, điểm mấu chốt là 'RRRR' không hoạt động tốt với các định dạng ngày khác:to_date('501212', 'rrrrmmdd') hurls
ora-01843:không phải là một tháng hợp lệ . So, use
'RR' and test for it before using
'VẬY'. Vì vậy, chức năng đã sửa đổi của tôi (với một số thu dọn) trông như thế này:
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;
/
Điểm mấu chốt vẫn là:có một giới hạn về mức độ thông minh mà chúng tôi có thể thực hiện chức năng này khi giải thích ngày tháng, vì vậy hãy đảm bảo rằng bạn dẫn đầu với sự phù hợp nhất. Nếu bạn nghĩ rằng hầu hết các chuỗi ngày của bạn phù hợp với ngày-tháng-năm, hãy đặt điều đó trước; bạn vẫn sẽ nhận được một số sai lầm nhưng ít hơn nếu bạn dẫn đầu với năm-tháng-ngày.