5

我有一个包含日期的数据集,并想检查日期顺序是否正确。

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

在提供日期的所有情况下,这应该满足:Date1 < Date2 < Date3 < Date4。当记录包含某些日期的 NULL 值时,应在非 NULL 日期之间进行检查。所以这就是我想要的结果:

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

我为此写了一个广泛的 CASE 声明,但必须有一个更优雅的解决方案:

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

有任何想法吗?

编辑:
我正在寻找一种解决方案,它允许比我上面给出的第一个示例中的三列更多的“日期”列(我的实际问题中有四个,并将其更改为三个以简化问题,但似乎我已经失去了这种简化的一个重要特征)。更新了四列的示例。

4

3 回答 3

7

您可以使用ISNULLandCOALESCE跳过空值。如果缺少日期,只需将其替换为始终通过检查的日期即可:

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

这假设您的“真实”日期当然永​​远不会超出 1900 - 3000 的范围;下一个千年虫正等着发生;)

编辑:编辑处理四个字段

于 2012-05-08T14:45:47.370 回答
1

您可以在比较日期的选择上使用大小写,并使用 ISNULL 函数,如果第一个参数不为空,则返回第一个参数,如果第一个参数为空,则返回第二个参数。

在这种情况下,我将开始日期设置为早期日期,将结束日期设置为旧日期

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
于 2012-05-08T14:52:43.857 回答
1

这是另一种方法:

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

这是输出:

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.

于 2012-05-10T09:22:34.337 回答