适用于 Oracle 12.2 的纯 SQL 解决方案,其中方便的 default null on conversion error 选项避免了编写函数和处理异常的需要:
with demo (date_string) as
( select '2018081' from dual union all
select '01/8/2018' from dual union all
select '01-8-2018' from dual union all
select 'ABCD' from dual union all
select '2018-08-01' from dual union all
select '2018-01-8' from dual union all
select '2017081' from dual union all
select '01-AUG-2018' from dual
)
select t.date_string
, coalesce
( to_date(t.date_string default null on conversion error)
, case sys_context('USERENV','NLS_TERRITORY')
when 'AMERICA' then to_date(t.date_string default null on conversion error,'MM/DD/YYYY')
else to_date(t.date_string default null on conversion error,'DD/MM/YYYY')
end
, to_date(t.date_string default null on conversion error,'DD/MM/YYYY')
, to_date(t.date_string default null on conversion error,'YYYY/MM/DD')
, to_date(t.date_string default null on conversion error,'YYYYMMDD')
, to_date(t.date_string default null on conversion error,'DD/MON/YYYY')
) as converted_date
from demo t
结果:
DATE_STRING CONVERTED_DATE
----------- --------------
2018081 01-AUG-2018
01/8/2018 08-JAN-2018
01-8-2018 08-JAN-2018
ABCD
2018-08-01 01-AUG-2018
2018-01-8 08-JAN-2018
2017081 01-AUG-2017
01-AUG-2018 01-AUG-2018
第一个测试没有指定任何格式以使用会话默认值(DD-MON-RRRR 等)。
下一个测试尝试处理北美将月份放在首位的习惯。 (我不确定sys_context('USERENV','NLS_TERRITORY') = 'AMERICA' 是否是一个可靠的测试,因为无论实际区域如何,这往往是默认设置。但是它说明了如何在需要时注入一些条件逻辑。)
to_date 对分隔符非常宽容,所以我没有为 DD-MON-YYYY 和 DD/MON/YYYY 等指定不同的格式。