首页 > 解决方案 > 简化 case 表达式中的 SQL case 语句

问题描述

我将如何在 T-SQL 中简化这个 case 语句?它提供了所需的结果,但非常笨重且难以阅读。我必须使用内部 case 语句将儒略日期(又名 6 位数字)转换为常规日期格式。

基本上我正在做一个日期差异(getdate(),案例陈述)。Getdate() 只返回现在的时间(即 2/27/2020),case 语句将儒略日期(即 123456)转换为正常日期(即 2020 年 1 月 1 日)。

如果查询是在 2 月 27 日今天运行的,这是预期的输出。

在此处输入图像描述

Select CASE 
        WHEN Datediff(day, Getdate(), CASE 
                    WHEN a.wadpl = 0
                        THEN NULL
                    ELSE Dateadd(d, Substring(Cast(wadpl AS VARCHAR(6)), 4, 3) - 1, CONVERT(DATETIME, CASE 
                                    WHEN LEFT(Cast(wadpl AS VARCHAR(6)), 1) = '1'
                                        THEN '20'
                                    ELSE '21'
                                    END + Substring(Cast(wadpl AS VARCHAR(6)), 2, 2) + '-01-01'))
                    END) < 0
            THEN 'Overdue Now'
        WHEN Datediff(day, Getdate(), CASE 
                    WHEN a.wadpl = 0
                        THEN NULL
                    ELSE Dateadd(d, Substring(Cast(wadpl AS VARCHAR(6)), 4, 3) - 1, CONVERT(DATETIME, CASE 
                                    WHEN LEFT(Cast(wadpl AS VARCHAR(6)), 1) = '1'
                                        THEN '20'
                                    ELSE '21'
                                    END + Substring(Cast(wadpl AS VARCHAR(6)), 2, 2) + '-01-01'))
                    END) <= 30
            THEN 'Coming due in 01-30 days'
        ELSE 'Not Overdue'
        END [Overdue Status]
FROM Table_X

标签: sqlsql-servertsqlcase

解决方案


这里很容易理解,假设 a.wadpl 是一个整数:

SELECT CASE 
  WHEN DATEDIFF(DAY, GETDATE(), DATEADD(DAY, a.wadpl % 1000, DATEADD(YEAR,a.wadpl / 1000,'1899-12-31'))) <0 THEN 'Overdue now'
  WHEN DATEDIFF(DAY, GETDATE(), DATEADD(DAY, a.wadpl % 1000, DATEADD(YEAR,a.wadpl / 1000,'1899-12-31'))) <= 30 THEN 'Coming due in 01-30 days'
  ELSE 'Not Overdue'
  END [Overdue Status]
FROM Table_X

或者您可以通过使用子查询来简化(或者您可以使用 WITH):

SELECT CASE 
  WHEN Age <0 THEN 'Overdue now'
  WHEN Age <= 30 THEN 'Coming due in 01-30 days'
  ELSE 'Not Overdue'
  END [Overdue Status]
FROM (
  SELECT DATEDIFF(DAY,GETDATE(),
    DATEADD(DAY,wadpl%1000,DATEADD(YEAR,wadpl/1000,'1899-12-31'))) Age, * 
  FROM Table_X) a

这当然会导致您对每一行进行此算术运算,并且您不能轻易使用任何索引。如果您询问聚合,那么我建议您做相反的事情,并预先计算日期并在您的查询中使用这些日期。您可能还需要考虑在 table_x 上放置一个持久计算列:

ALTER TABLE TABLE_X
ADD wadpl_dt AS
  (DATEADD(DAY,wadpl%1000,DATEADD(YEAR,wadpl/1000,'1899-12-31'))) PERSISTED;

现在,您可以在需要日期时间的任何时候参考 table_x.wadpl_dt,您的查询将变为:

SELECT CASE 
  WHEN Age <0 THEN 'Overdue now'
  WHEN Age <= 30 THEN 'Coming due in 01-30 days'
  ELSE 'Not Overdue'
  END [Overdue Status]
FROM (
  SELECT DATEDIFF(DAY,GETDATE(), wadpl_dt) Age, * 
  FROM Table_X) a

这是将日期转换为儒略日期的简单方法:

SELECT (DATEPART(YEAR,GETDATE())-1900) * 1000 + DATEPART(DAYOFYEAR, GETDATE())

这就是你可以使用它的方式:

DECLARE @overdue int;
DECLARE @next30 int;

SET @overdue = (SELECT (DATEPART(YEAR,GETDATE())-1900) * 1000 + DATEPART(DAYOFYEAR, GETDATE()));
SET @next30 = (SELECT (DATEPART(YEAR,GETDATE()+30)-1900) * 1000 + DATEPART(DAYOFYEAR, GETDATE()+30));
SELECT CASE 
  WHEN wadpl < @overdue THEN 'Overdue now'
  WHEN wadpl <= @next30 THEN 'Coming due in 01-30 days'
  ELSE 'Not Overdue'
  END [Overdue Status]
FROM Table_X

推荐阅读