Case When语句

时间:2016-04-18 19:46:44

标签: sql-server compiler-errors null type-conversion

我正在尝试查看4个日期字段并选择最新的字段。一切都很好,直到我在一个没有任何东西的地方。然后我得到了一个

  

“从字符串转换日期和/或时间时转换失败。”错误。

有没有办法忽略空值?

Select AP.ID, AP.CERT_DATE as 'Cert Date', AP.Recert_Date as 'Recert Date', AP.Recert_Date2 as 'Recert Date 2', AP.Recert_Date3 as 'Recert Date 3',
CASE    
    When AP.CERT_DATE > AP.Recert_Date AND AP.CERT_DATE > AP.Recert_Date2 AND AP.CERT_DATE > AP.Recert_Date3 Then AP.CERT_DATE
    When AP.Recert_Date > AP.CERT_DATE AND AP.Recert_Date > AP.Recert_Date2 AND AP.Recert_Date > AP.Recert_Date3 Then AP.Recert_Date
    When AP.Recert_Date2 > AP.CERT_DATE AND AP.Recert_Date2 > AP.Recert_Date AND AP.Recert_Date2 > AP.Recert_Date3 Then AP.Recert_Date2
    When AP.Recert_Date3 > AP.CERT_DATE AND AP.Recert_Date3 > AP.Recert_Date AND AP.Recert_Date3 > AP.Recert_Date2 Then AP.Recert_Date3
    ELSE 'Attention'
END AS 'Most Recent Year'
FROM Profile AP

2 个答案:

答案 0 :(得分:1)

如果您使用的是SQL Server 2012或更高版本,则开发人员更友好的方法是使用TRY_CONVERT,它允许检查(n)varchar是否表示特定格式的有效日期时间。

应用Javier的回答,你可以这样:

declare @minDate DATE = '19000101'

(SELECT Max(d) FROM (VALUES 
    (ISNULL(TRY_CONVERT(DATETIME, CERT_DATE), @minDate), 
    (Recert_Date), 
    (Recert_Date2), 
    (Recert_Date3)
) AS value(d)) as 'Most Recent Year'

(仅适用于varchars的TRY_CONVERT

但是,如果可能,请尝试将所有日期列设为DATEDATETIME2,而不是VARCHAR

答案 1 :(得分:0)

如果您使用的是MSSQL 2008或更高版本,可以尝试一下吗?

SELECT AP.ID, AP.CERT_DATE as 'Cert Date', AP.Recert_Date as 'Recert Date', AP.Recert_Date2 as 'Recert Date 2', AP.Recert_Date3 as 'Recert Date 3',
  (SELECT Max(d) 
   FROM (VALUES (CERT_DATE), (Recert_Date), (Recert_Date2), (Recert_Date3)) AS value(d)) as 'Most Recent Year'
FROM Profile AP

顺便说一下,关于您的错误,when语句中的所有字段都是date类型,字段else语句是varchar。您无法在案例结构中组合不同的类型。您应该将else字段更改为默认日期而不是字符串,或者将when语句中的所有字段转换为varchar

恕我直言,你的查询难以阅读且难以管理,所以我建议使用上面提到的替代查询。

编辑:如果你想进一步处理这个新专栏你可以做这样的事情(阿列克谢的例子更清洁):

SELECT A.ID, A.CERT_DATE as 'Cert Date', A.Recert_Date as 'Recert Date', A.Recert_Date2 as 'Recert Date 2', A.Recert_Date3 as 'Recert Date 3'
, ISNULL(CAST(MaxDate as varchar),'Attention') -- I would prefer following Alexei's approach by declaring previously a mindate variable and do:  ISNULL(MaxDate, @MinDate) -- That way you can keep the date type output
, DATEDIFF (YY, MaxDate, GETDATE())
, Case When DATEADD (YY, DateDiff (YY, MaxDate, GETDATE()), MaxDate) > GETDATE () Then 1 Else 0 End
FROM 
(
SELECT AP.ID, AP.CERT_DATE, AP.Recert_Date, AP.Recert_Date2, AP.Recert_Date3
      (SELECT Max(d) 
       FROM (VALUES (CERT_DATE), (Recert_Date), (Recert_Date2), (Recert_Date3)) AS value(d)) as 'MaxDate'
    FROM Profile AP
) A

在一天结束时,您将始终在同一个地方。您不能在同一列上组合varchar和日期类型。这就是为什么你需要将一个或另一个投射到另一种类型。 应用于Alexei的建议您可以使用默认的@MinDate,以便稍后检查该值并显示全局化的消息(如果您从.NET运行SP)