我们如何只从 Oracle 中具有各种日期和字符串格式的列中提取日期?
How can we extract date only from a column with various date and string formats in Oracle?
ACTUAL
expected
SEP-10-2017
10-SEP-2017
SEP 30 2018
30-SEP-2018
OFFICE OF SMALL
OCT-11-2018
11-OCT-2018
O9-SEP-2009
O9-SEP-2009
Not Applicable
NOV-20-2001
20-NOV-2001
BANIJYA BHIBAG
AUGUST 03 2017
03-AUG-2017
AUG-04-1991
04-AUG-1991
97/2015
09/09/2018
09-SEP-2018
如何才能得到如上的结果,并丢弃无法转换的日期?
一个选择是创建一个涵盖所有 种可能组合的函数。以下示例包含其中一些 - 您必须在找到它们时添加新的。
SQL> create or replace function f_date (par_str in varchar2)
2 return date
3 is
4 l_date date;
5 begin
6 begin
7 l_date := to_date(par_str, 'mon-dd-yyyy');
8 return l_date;
9 exception
10 when others then null;
11 end;
12
13 --
14
15 begin
16 l_date := to_date(par_str, 'mon dd yyyy');
17 return l_date;
18 exception
19 when others then null;
20 end;
21
22 --
23
24 begin
25 l_date := to_date(par_str, 'dd-mon-yyyy');
26 return l_date;
27 exception
28 when others then null;
29 end;
30
31 --
32
33 begin
34 l_date := to_date(par_str, 'month dd yyyy');
35 return l_date;
36 exception
37 when others then null;
38 end;
39
40 --
41
42 begin
43 l_date := to_date(par_str, 'dd/mm/yyyy');
44 return l_date;
45 exception
46 when others then null;
47 end;
48
49 return null;
50
51 exception
52 when others then
53 return null;
54 end f_date;
55 /
Function created.
测试:
SQL> select actual, f_date(actual) as expected
2 from test;
ACTUAL EXPECTED
--------------- -----------
SEP-10-2017 10-SEP-2017
SEP 30 2018 30-SEP-2018
OFFICE OF SMALL
09-SEP-2009 09-SEP-2009
Not applicable
AUGUST 03 2017 03-AUG-2017
97/2015
09/09/2018 09-SEP-2018
8 rows selected.
SQL>
可能出现的问题:如果actual = 09/10/12
,什么是什么?
- 09 可以是日、月或年
- 10也可以是日月年
- 12也可以是日月年
那么,它是什么?
- 2012 年 10 月 9 日
- 2012 年 9 月 10 日
- 2009 年 10 月 12 日
- ...
如果您确定您没有任何其他类型的格式可以转换为日期值(eg.all 数据符合此示例数据集) , 然后使用下面的代码块来填充另一个 table(t2
) 与体面的日期值同时显示烂值如
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
dt DATE;
BEGIN
FOR c IN (SELECT * FROM t) LOOP
BEGIN
dt := TO_DATE(c.col, 'MON-DD-YYYY', 'NLS_DATE_LANGUAGE=ENGLISH');
INSERT INTO t2 VALUES(c.id,c.col);
EXCEPTION
WHEN OTHERS THEN
BEGIN
dt := TO_DATE(c.col, 'DD/MM/YYYY', 'NLS_DATE_LANGUAGE=ENGLISH');
INSERT INTO t2 VALUES(c.id,c.col);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(c.col || ' is not a valid date value');
END;
END;
END LOOP;
COMMIT;
END;
/
从 Oracle 12 开始,您不需要 PL/SQL 并且可以使用:
SELECT actual,
COALESCE(
TO_DATE(
actual DEFAULT NULL ON CONVERSION ERROR,
'MM-DD-YYYY',
'NLS_DATE_LANGUAGE=ENGLISH'
),
TO_DATE(
actual DEFAULT NULL ON CONVERSION ERROR,
'DD-MON-YYYY',
'NLS_DATE_LANGUAGE=ENGLISH'
)
) AS parsed
FROM table_name;
其中,对于示例数据:
CREATE TABLE table_name (ACTUAL) AS
SELECT 'SEP-10-2017' FROM DUAL UNION ALL
SELECT 'SEP 30 2018' FROM DUAL UNION ALL
SELECT 'OFFICE OF SMALL' FROM DUAL UNION ALL
SELECT 'OCT-11-2018' FROM DUAL UNION ALL
SELECT 'O9-SEP-2009' FROM DUAL UNION ALL
SELECT 'Not Applicable' FROM DUAL UNION ALL
SELECT 'NOV-20-2001' FROM DUAL UNION ALL
SELECT 'BANIJYA BHIBAG' FROM DUAL UNION ALL
SELECT 'AUGUST 03 2017' FROM DUAL UNION ALL
SELECT 'AUG-04-1991' FROM DUAL UNION ALL
SELECT '97/2015' FROM DUAL UNION ALL
SELECT '09/09/2018' FROM DUAL;
输出:
ACTUAL
PARSED
SEP-10-2017
10-SEP-2017
SEP 30 2018
30-SEP-2018
OFFICE OF SMALL
OCT-11-2018
11-OCT-2018
O9-SEP-2009
Not Applicable
NOV-20-2001
20-NOV-2001
BANIJYA BHIBAG
AUGUST 03 2017
03-AUG-2017
AUG-04-1991
04-AUG-1991
97/2015
09/09/2018
09-SEP-2018
注意:O9-SEP-2009
尚未解析,因为您的第一个字符是字母 O
而不是数字 0
。
db<>fiddle here
ACTUAL | expected |
---|---|
SEP-10-2017 | 10-SEP-2017 |
SEP 30 2018 | 30-SEP-2018 |
OFFICE OF SMALL | |
OCT-11-2018 | 11-OCT-2018 |
O9-SEP-2009 | O9-SEP-2009 |
Not Applicable | |
NOV-20-2001 | 20-NOV-2001 |
BANIJYA BHIBAG | |
AUGUST 03 2017 | 03-AUG-2017 |
AUG-04-1991 | 04-AUG-1991 |
97/2015 | |
09/09/2018 | 09-SEP-2018 |
如何才能得到如上的结果,并丢弃无法转换的日期?
一个选择是创建一个涵盖所有 种可能组合的函数。以下示例包含其中一些 - 您必须在找到它们时添加新的。
SQL> create or replace function f_date (par_str in varchar2)
2 return date
3 is
4 l_date date;
5 begin
6 begin
7 l_date := to_date(par_str, 'mon-dd-yyyy');
8 return l_date;
9 exception
10 when others then null;
11 end;
12
13 --
14
15 begin
16 l_date := to_date(par_str, 'mon dd yyyy');
17 return l_date;
18 exception
19 when others then null;
20 end;
21
22 --
23
24 begin
25 l_date := to_date(par_str, 'dd-mon-yyyy');
26 return l_date;
27 exception
28 when others then null;
29 end;
30
31 --
32
33 begin
34 l_date := to_date(par_str, 'month dd yyyy');
35 return l_date;
36 exception
37 when others then null;
38 end;
39
40 --
41
42 begin
43 l_date := to_date(par_str, 'dd/mm/yyyy');
44 return l_date;
45 exception
46 when others then null;
47 end;
48
49 return null;
50
51 exception
52 when others then
53 return null;
54 end f_date;
55 /
Function created.
测试:
SQL> select actual, f_date(actual) as expected
2 from test;
ACTUAL EXPECTED
--------------- -----------
SEP-10-2017 10-SEP-2017
SEP 30 2018 30-SEP-2018
OFFICE OF SMALL
09-SEP-2009 09-SEP-2009
Not applicable
AUGUST 03 2017 03-AUG-2017
97/2015
09/09/2018 09-SEP-2018
8 rows selected.
SQL>
可能出现的问题:如果actual = 09/10/12
,什么是什么?
- 09 可以是日、月或年
- 10也可以是日月年
- 12也可以是日月年
那么,它是什么?
- 2012 年 10 月 9 日
- 2012 年 9 月 10 日
- 2009 年 10 月 12 日
- ...
如果您确定您没有任何其他类型的格式可以转换为日期值(eg.all 数据符合此示例数据集) , 然后使用下面的代码块来填充另一个 table(t2
) 与体面的日期值同时显示烂值如
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
dt DATE;
BEGIN
FOR c IN (SELECT * FROM t) LOOP
BEGIN
dt := TO_DATE(c.col, 'MON-DD-YYYY', 'NLS_DATE_LANGUAGE=ENGLISH');
INSERT INTO t2 VALUES(c.id,c.col);
EXCEPTION
WHEN OTHERS THEN
BEGIN
dt := TO_DATE(c.col, 'DD/MM/YYYY', 'NLS_DATE_LANGUAGE=ENGLISH');
INSERT INTO t2 VALUES(c.id,c.col);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(c.col || ' is not a valid date value');
END;
END;
END LOOP;
COMMIT;
END;
/
从 Oracle 12 开始,您不需要 PL/SQL 并且可以使用:
SELECT actual,
COALESCE(
TO_DATE(
actual DEFAULT NULL ON CONVERSION ERROR,
'MM-DD-YYYY',
'NLS_DATE_LANGUAGE=ENGLISH'
),
TO_DATE(
actual DEFAULT NULL ON CONVERSION ERROR,
'DD-MON-YYYY',
'NLS_DATE_LANGUAGE=ENGLISH'
)
) AS parsed
FROM table_name;
其中,对于示例数据:
CREATE TABLE table_name (ACTUAL) AS
SELECT 'SEP-10-2017' FROM DUAL UNION ALL
SELECT 'SEP 30 2018' FROM DUAL UNION ALL
SELECT 'OFFICE OF SMALL' FROM DUAL UNION ALL
SELECT 'OCT-11-2018' FROM DUAL UNION ALL
SELECT 'O9-SEP-2009' FROM DUAL UNION ALL
SELECT 'Not Applicable' FROM DUAL UNION ALL
SELECT 'NOV-20-2001' FROM DUAL UNION ALL
SELECT 'BANIJYA BHIBAG' FROM DUAL UNION ALL
SELECT 'AUGUST 03 2017' FROM DUAL UNION ALL
SELECT 'AUG-04-1991' FROM DUAL UNION ALL
SELECT '97/2015' FROM DUAL UNION ALL
SELECT '09/09/2018' FROM DUAL;
输出:
ACTUAL PARSED SEP-10-2017 10-SEP-2017 SEP 30 2018 30-SEP-2018 OFFICE OF SMALL OCT-11-2018 11-OCT-2018 O9-SEP-2009 Not Applicable NOV-20-2001 20-NOV-2001 BANIJYA BHIBAG AUGUST 03 2017 03-AUG-2017 AUG-04-1991 04-AUG-1991 97/2015 09/09/2018 09-SEP-2018
注意:O9-SEP-2009
尚未解析,因为您的第一个字符是字母 O
而不是数字 0
。
db<>fiddle here