10

我正在修改一个查询,这是我的脚本:

select 
CASE When EndDate='1/1/1900' 
THEN NULL 
ELSE EndDate END,*
from Members

该脚本只是比较日期,如果是“1/1/1900”则返回null,否则返回日期。

我可以在我的数据库中看到日期以以下格式存储:

1900-01-01 00:00:00.000

问题是当我的模式与存储的模式不同时,SQL Server 如何像这样匹配日期。同样在日期格式中,我没有传递时间元素。

4

1 回答 1

19

'1/1/1900'由于数据类型的优先级,SQL Server 将您传递的字符串文字 ( ) 转换为日期时间值(因为日期时间的优先级高于字符串类型)。如果您传递一个无效的日期作为您的字符串,例如'2/31/1900',您将收到一个转换错误 ( Msg 242),因为 SQL Server 不知道 2 月 31 日的含义。它不会尝试匹配看起来像您传递的字符串,它会将两者都转换为日期的内部表示(在我的评论中有更多内容)。

在专门处理日期时,不要考虑格式,除非您传递字符串文字,m/d/y(或者那是d/m/y?)是一种糟糕的格式。使用更安全:

YYYYMMDD

您的查询应为:

SELECT CASE When EndDate = '19000101' 
 THEN NULL ELSE EndDate END, ...other columns...
FROM dbo.Members;

这样,当您通过像 9 月 8 日这样的日期时,它不会被 SQL Server 和其他读者等误解。是09/08/20139 月 8 日还是 8 月 9 日?取决于你在世界的哪个角落,对吧?在您的情况下,这没关系,因为日期和月份是相同的,但情况并非总是如此。请参阅以下文章:

(请,请,请完整阅读该链接。)

最后,如果您正在使用DATETIME/SMALLDATETIME并且正在查找特定日期的值,则根本不应该使用相等,而应该使用范围查询。例如,要查找EndDate2013 年 4 月 15 日的所有行,无论时间如何,您会说:

WHERE EndDate >= '20130415'
  AND EndDate <  '20130416'

阅读此链接以了解您不想在BETWEEN此处使用的原因。)

如果您使用的是 SQL Server 2008 或更高版本,您仍然可以使用 实现此列的可搜索性CONVERT,但这是一个罕见的例外 - 通常您不想对列使用函数。

WHERE CONVERT(DATE, EndDate) = '20130415'

其他一些评论 - 与您的问题没有直接关系,而是对您的代码的外围观察:

  1. 始终使用架构前缀
  2. 切勿SELECT *在生产中使用
于 2013-04-16T01:02:13.477 回答