I've got a data set with dates and want to check if the date order is correct.
RecordID Date1 Date2 Date3 Date4
1 2011-05-10 2011-08-16 NULL 2011-11-22
2 NULL 2012-02-03 2012-02-27 2012-03-05
3 2011-05-30 2011-05-11 2011-08-17 2011-09-15
4 2011-05-30 NULL NULL NULL
In all cases when dates are provided, this should hold: Date1 < Date2 < Date3 < Date4. When the record contains NULL values for certain dates, the check should be made between the dates that are not NULL. So this is the result I want:
RecordID Date1 Date2 Date3 Date4 CheckDates
1 2011-05-10 2011-08-16 NULL 2011-11-22 correct
2 NULL 2012-02-03 2012-02-27 2012-03-05 correct
3 2011-05-30 2011-05-11 2011-08-17 2011-09-15 incorrect
4 2011-05-30 NULL NULL NULL correct
I've written an extensive CASE statement for this, but there must be a more elegant solution:
CASE
WHEN Date1 IS NULL AND Date2 IS NULL AND Date3 IS NULL AND Date4 IS NULL THEN 'correct'
WHEN Date1 IS NULL AND Date2 IS NULL AND Date3 IS NULL AND Date4 IS NOT NULL THEN 'correct'
WHEN Date1 IS NULL AND Date2 IS NULL AND Date3 IS NOT NULL AND Date4 IS NULL THEN 'correct'
WHEN Date1 IS NULL AND Date2 IS NULL AND Date3 IS NOT NULL AND Date4 IS NOT NULL AND Date3 < Date4 THEN 'correct'
...
ELSE 'incorrect'
END
Any ideas?
EDIT:
I am looking for a solution that allows for more 'Date' columns than the three columns in the first example I gave above (I've got four in my real-world problem, and changed it to three to simplify the problem, but seems I've lost a significant characteristic with this simplification). Updated the example for four columns.
You can use ISNULL
and COALESCE
to skip over the null values. If the date is missing, just replace it with a date that will always pass the check:
CASE
WHEN (ISNULL(Date1, '01/01/1900') < COALESCE(Date2, Date3, Date4, '01/01/3000'))
AND (ISNULL(Date2, '01/01/1900') < COALESCE(Date3, Date4, '01/01/3000'))
AND (ISNULL(Date3, '01/01/1900') < COALESCE(Date4, '01/01/3000'))
THEN 'correct'
ELSE 'incorrect'
END
This assumes your "real" dates would never go outside the rage 1900 - 3000 of course; there's the next millenium bug just waiting to happen ;)
EDIT: Edited to handle four fields
you can use the case on the select comparing the dates and use the ISNULL function that returns the first parameter if it isnt null or the second if the firs is null.
In this case I've set the start dates as an early date and the end date as an old date
select date1,date2,date3,
case
when isnull(date1,'01/01/1900') <isnull(date2,'01/01/2100') and isnull(date2,'01/01/1900') <isnull(date3,'2100') then 'OK'
else 'not OK'
end
from testDates
Here's another approach:
WITH data (
RecordID, Date1 , Date2 , Date3 , Date4
) AS (
SELECT 1, '2011-05-10','2011-08-16', NULL ,'2011-11-22' UNION ALL
SELECT 2, NULL ,'2012-02-03','2012-02-27','2012-03-05' UNION ALL
SELECT 3, '2011-05-30','2011-05-11','2011-08-17','2011-09-15' UNION ALL
SELECT 4, '2011-05-30', NULL , NULL , NULL
)
SELECT
*,
CheckDates = (
SELECT
MAX(CASE IdRank WHEN DateRank THEN 'correct' ELSE 'incorrect' END)
FROM (
SELECT
IdRank = ROW_NUMBER() OVER (ORDER BY ID),
DateRank = ROW_NUMBER() OVER (ORDER BY Date)
FROM (
VALUES
(1, Date1),
(2, Date2),
(3, Date3),
(4, Date4)
) s (ID, Date)
WHERE Date IS NOT NULL
) s
)
FROM data
Here's the output:
RecordID Date1 Date2 Date3 Date4 CheckDates
----------- ---------- ---------- ---------- ---------- ----------
1 2011-05-10 2011-08-16 NULL 2011-11-22 correct
2 NULL 2012-02-03 2012-02-27 2012-03-05 correct
3 2011-05-30 2011-05-11 2011-08-17 2011-09-15 incorrect
4 2011-05-30 NULL NULL NULL correct
The checking expression is more complicated than the one in @njr's answer, but, I guess, it pays off when you need to scale the script to support more columns: you'd just need to add new rows after the VALUES
clause.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With