I want to thank you in advance for your help on this matter.
I'm writing a SQL query in Oracle SQL Developer which needs to compare 3 dates and return the earliest one, avoiding blank values and writing that value somewhere along the lines.
My question is what do you think is the best way to avoid those NULL values, my take is below but I'm having some slight issues implementing this in my current setup.
Cheers!
SELECT Case When DATE1 < DATE2 And DATE1 < DATE3 Then DATE1
When DATE2 < DATE1 And DATE2 < DATE3 Then DATE2
Else DATE3
End AS xxx, SOME.TABLE|| ' ' || TABLE.SOME INTO TABLE1, TABLE2
FROM (SELECT Case When DATE1 IS NULL Then DATEADD(year, 100, GETDATE()) Else DATE1 As DATE1,
Case When DATE2 IS NULL Then DATEADD(year, 100, GETDATE()) Else DATE2 As DATE2,
Case When DATE3 IS NULL Then DATEADD(year, 100, GETDATE())
Else DATE3 As DATE3
FROM SOME_TABLE2 ST2 WHERE SOME_TABLE3 = '#INTO_SOMETHING')
CodePudding user response:
You can use LEAST
and COALESCE
:
SELECT LEAST(
COALESCE(date1, date2, date3, ADD_MONTHS(SYSDATE, 100*12)),
COALESCE(date2, date3, date1, ADD_MONTHS(SYSDATE, 100*12)),
COALESCE(date3, date1, date2, ADD_MONTHS(SYSDATE, 100*12))
) AS least_date
FROM table_name;
or:
SELECT COALESCE(
LEAST(
COALESCE(date1, date2, date3),
COALESCE(date2, date3, date1),
COALESCE(date3, date1, date2)
),
ADD_MONTHS(SYSDATE, 100*12)
) AS least_date
FROM table_name;
or:
SELECT LEAST(
COALESCE(date1, ADD_MONTHS(SYSDATE, 100*12)),
COALESCE(date2, ADD_MONTHS(SYSDATE, 100*12)),
COALESCE(date3, ADD_MONTHS(SYSDATE, 100*12))
) AS least_date
FROM table_name;
Note: the first two queries will return the least non-NULL
value from your table in preference to the default value 100 years from now. The final query may return the default value 100 years from now if all the other values are a mix of NULL
and non-NULL
values that are greater than 100 years from now. Which you use depends on the logic you want to implement and whether your table will ever contain dates more than 100 years in the future.
Which, for the sample data:
CREATE TABLE table_name (date1, date2, date3) AS
SELECT DATE '2022-01-01', DATE '2021-01-01', DATE '2020-01-01' FROM DUAL UNION ALL
SELECT DATE '2022-01-01', NULL, DATE '2020-01-01' FROM DUAL UNION ALL
SELECT DATE '2022-01-01', DATE '2021-01-01', NULL FROM DUAL UNION ALL
SELECT NULL, DATE '2021-01-01', NULL FROM DUAL UNION ALL
SELECT NULL, NULL, NULL FROM DUAL;
All output:
LEAST_DATE |
---|
2020-01-01 00:00:00 |
2020-01-01 00:00:00 |
2021-01-01 00:00:00 |
2021-01-01 00:00:00 |
2122-12-05 09:50:28 |
If you do want a NULL
value if, and only if, all 3 dates are NULL
then use the first query without the default date:
SELECT LEAST(
COALESCE(date1, date2, date3),
COALESCE(date2, date3, date1),
COALESCE(date3, date1, date2)
) AS least_date
FROM table_name;
CodePudding user response:
Here is a little paralel results Using LEAST() function alone, with Nvl() and CASE with Nvl. The Last one will return Null if all 3 date columns are Null.
Sample data:
WITH
tbl As
(
Select 1 "NMBR", 'A' "LTTR", SYSDATE "DATE1", SYSDATE-1 "DATE2", SYSDATE 1 "DATE3" From Dual Union All
Select 2 "NMBR", 'B' "LTTR", SYSDATE "DATE1", SYSDATE-1 "DATE2", Null "DATE3" From Dual Union All
Select 3 "NMBR", 'C' "LTTR", SYSDATE "DATE1", Null "DATE2", SYSDATE 1 "DATE3" From Dual Union All
Select 4 "NMBR", 'D' "LTTR", Null "DATE1", SYSDATE-1 "DATE2", SYSDATE 1 "DATE3" From Dual Union All
Select 5 "NMBR", 'E' "LTTR", Null "DATE1", Null "DATE2", SYSDATE 1 "DATE3" From Dual Union All
Select 6 "NMBR", 'F' "LTTR", Null "DATE1", Null "DATE2", NULL "DATE3" From Dual
)
NMBR | LTTR | DATE1 | DATE2 | DATE3 |
---|---|---|---|---|
1 | A | 05-DEC-22 | 04-DEC-22 | 06-DEC-22 |
2 | B | 05-DEC-22 | 04-DEC-22 | |
3 | C | 05-DEC-22 | 06-DEC-22 | |
4 | D | 04-DEC-22 | 06-DEC-22 | |
5 | E | 06-DEC-22 | ||
6 | F |
SQL
SELECT
NMBR,
LTTR,
LEAST(DATE1, DATE2, DATE3) "LEAST_DATE",
LEAST(Nvl(DATE1, TRUNC(SYSDATE) 10000), Nvl(DATE2, TRUNC(SYSDATE) 10000), Nvl(DATE3, TRUNC(SYSDATE) 10000)) "LEAST_NVL_DATE",
CASE
WHEN LEAST(Nvl(DATE1, TRUNC(SYSDATE) 10000), Nvl(DATE2, TRUNC(SYSDATE) 10000), Nvl(DATE3, TRUNC(SYSDATE) 10000)) < TRUNC(SYSDATE 1000)
THEN LEAST(Nvl(DATE1, TRUNC(SYSDATE) 10000), Nvl(DATE2, TRUNC(SYSDATE) 10000), Nvl(DATE3, TRUNC(SYSDATE) 10000))
END "LEAST_CASE_NVL_DATE"
FROM
tbl
Result:
NMBR | LTTR | LEAST_DATE | LEAST_NVL_DATE | LEAST_CASE_NVL_DATE |
---|---|---|---|---|
1 | A | 04-DEC-22 | 04-DEC-22 | 04-DEC-22 |
2 | B | 04-DEC-22 | 04-DEC-22 | |
3 | C | 05-DEC-22 | 05-DEC-22 | |
4 | D | 04-DEC-22 | 04-DEC-22 | |
5 | E | 06-DEC-22 | 06-DEC-22 | |
6 | F | 22-APR-50 |
CodePudding user response:
I've been able to resolve the issue by using LEAST and COALESCE functions, since DATEADD and GETDATE are not Oracle functions.
Further to this, I've used @MT0 resolution query which worked well in my current setup.