我们有一个传入文件,其中有一个字段,该字段是保存日期值的字符串。字符串(日期值)可以是任意数量的格式。我们需要首先将该值转换为日期,以便我们可以按照我们需要的方式格式化该日期。
在 SQL Server 中我们可以:
SELECT FORMAT(CAST('stringvalue' as date),'yyyyMM') AS MyDate
这几乎适用于我们尝试过的不同类型日期格式的所有测试用例。
但是,ORACLE 似乎您需要首先了解 StringValue 的日期格式,然后才能成功转换它。
SELECT to_char(to_date('stringvalue','MM/DD/YYYY'),'YYYYMM') AS dt
from dual;
在 ORACLE 中我们有什么办法可以在不知道上面的“MM/DD/YYYY”部分的情况下做到这一点吗??
如果你想获取不同掩码中的日期,则没有办法做到这一点。如果您想避免使用掩码,只有一种方法可以做到这一点,但它会影响该会话中的所有语句。您可以指定会话级别 nls_date_format,然后使用 CAST 您不需要指定任何掩码
SQL> alter session set nls_date_format='dd/mm/yyyy' ;
Session altered.
SQL> select cast('10/01/2020' as date) from dual ;
CAST('10/0
----------
10/01/2020
但是,它不会接受任何其他掩码,因为采用默认掩码
SQL> select cast('2020/01/10' as date) from dual ;
select cast('2020/01/10' as date) from dual
*
ERROR at line 1:
ORA-01861: literal does not match format string
但这在 SQL Server 中也会发生。 SQL SERVER 函数 FORMAT(CAST string as date) mask ) 或多或少执行相同的操作,但顺序相反。
让我举个例子来说明
SELECT CAST('03/11/2020' AS date);
2020-03-11
它返回 11 月 3 日,而对我来说,我指的是 3 月 11 日。为什么 ?因为 SQL Server 也会在 SET DATEFORMAT 中中继来更改日期格式的会话级别设置。
没有任何计算语言可以做到这一点。必须隐式或显式提供掩码。 SQL 与任何其他语言一样,无法理解我所说的 3/11 的含义(无论是 11 月 3 日还是 3 月 11 日,两者都可以)。
您可以尝试分析您的文本值,以查看您拥有哪种日期格式。
执行类似操作的示例查询如下所示:
WITH subq AS (
SELECT
txt_date_value,
REGEXP_REPLACE(REGEXP_REPLACE(txt_date_value, '[a-zA-Z]', 'A'), '\d', 'd') AS reg_reduced
FROM data_table
)
SELECT
reg_reduced,
COUNT(1),
MIN(txt_date_value),
MAX(txt_date_value)
FROM subq
GROUP BY reg_reduced
ORDER BY 1
;
一旦获得(最有可能的)日期格式列表,您可以将它们全部放入存储函数(当然,作为正确格式的正则表达式)以根据这些格式转换为日期:
CREATE OR REPLACE FUNCTION text_to_date(p_date_str IN VARCHAR2) RETURN DATE
IS
v_format VARCHAR2(15) := 'OTHER';
BEGIN
v_format :=
CASE
WHEN REGEXP_LIKE (p_date_str, '\d{4}\-\d{1,2}\-\d{1,2}')
THEN
'yyyy-mm-dd'
WHEN REGEXP_LIKE (p_date_str, '\d{1,2}\-\d{1,2}\-\d{4}')
THEN
'mm-dd-yyyy'
WHEN REGEXP_LIKE (p_date_str, '\d{1,2} [A-Za-z]{3} \d{4}')
THEN
'dd MON yyyy'
ELSE
'OTHER'
END;
IF v_format = 'OTHER' THEN
RETURN NULL;
ELSE
RETURN to_date(p_date_str, v_format);
END IF;
EXCEPTION
WHEN OTHERS THEN
RETURN NULL;
END;
根据需要添加到 v_format CASE 语句。