Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check nullable date values for correct order

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.

like image 381
Josien Avatar asked May 08 '12 14:05

Josien


3 Answers

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

like image 156
njr101 Avatar answered Oct 19 '22 18:10

njr101


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
like image 33
Diego Avatar answered Oct 19 '22 17:10

Diego


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.

like image 23
Andriy M Avatar answered Oct 19 '22 18:10

Andriy M