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 |
how can we get the result as above and discard the date that cannot be converted?
CodePudding user response:
From Oracle 12, you do not need PL/SQL and can use:
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;
Which, for the sample data:
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;
Outputs:
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
Note: O9-SEP-2009
has not parsed because you have the letter O
rather than the digit 0
as the first character.
db<>fiddle here
CodePudding user response:
One option is to create a function which will cover all possible combinations. The following example has some of them - you'd have to add new when you find them.
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.
Testing:
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>
Possible problems: if actual = 09/10/12
, what is what?
- 09 can be day, month or year
- 10 can also be day, month or year
- 12 can also be day, month or year
So, what is it?
- 09-OCT-2012
- 10-SEP-2012
- 12-OCT-2009
- ...
CodePudding user response:
If you're sure about that you don't have any other type of the format for those values which can be convertible to a date value(eg.all of the data conform with this sample data set), then use the following code block in order to populate another table(t2
) with the decent date values while displaying the rotten values such as
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;
/