<p>经常会遇到查询指定日期的记录,而仅仅输入日期,与表中的时间进行匹配时,颇有些麻烦。仅摘抄一段,说明针对此问题的两种解决方案。</p>

假设想要了解今天所有订单的情况。使用以下查询试试看:

SELECT *
FROM Orders
WHERE OrderDate = GetDate();

遗憾的是,这个查询并不能返回任何数据。这是因为GETDATE()函数获得的是精确到毫秒的时间,而不只是日期。这意味着任何基于GETDATE()的查询都不能返回任何数据,即使是发生在同一天也不行(对于smalldatetime字段来说,可能发生在同一分钟,对于datetime字段来说可能发生在同一毫秒,对于datetime2字段来说,可能接近100毫秒)。

常见的解决方案是把日期转换为字符串并转换回来以截断时间,然后作比较。

代码如下所示:

SELECT * 
FROM Orders
WHERE CONVERT(varchar(12), OrderDate, 101) = CONVERT(varchar(12), GETDATE(), 101)

注意:

也可以只是将@Date的值强制转换为date数据类型。这里选择使用CONVERT,只是为了选择使用一种向后兼容的截断日期的方法(SQL Server 2005 及更早的版本不支持date数据类型)。

这次,无论订单的时间如何,都将得到OrderDate列中今天的日期的所有数据行。可惜的是,这些代码的可读性并不是最好的。想象一下,如果有一大串的日期需要作这类比较——其结果肯定是可读性不好。

现在使用一个简单的用户自定义函数来实现这个功能。首先,需要创建实际的函数。这通过CREATE FUNCTION命令完成,它的格式和存储过程很像。例如,创建这个函数的代码如下:

CREATE FUNCTION dbo.DayOnly(@Date date)
RETURNS date
AS
BEGIN
	RETURN @Date;
END

其中,从GETDATE()返回的日期将作为参数传入,而且函数体内将包含转换日期的工作,最后将返回截取的日期值。

注意,上述的版本是一个SQL Server 2008兼容版本,这依赖于强制转换为参数的date数据类型来截断时间。如果想在SQL Server 2005进行这样的截断(就像基于查询的示例中所做的那样),需要像前面一样使用CONVERT函数。例如:

CREATE FUNCTION dbo.DayOnly(@Date datetime)
RETURNS varchar(12)
AS
BEGIN
	RETURN CONVERT(varchar(12), @Date, 101);
END

为了看一下这个函数的效果,这里稍微修改一下查询:

SELECT * 
FROM Orders
WHERE dbo.DayOnly(OrderDate) = dbo.DayOnly(GETDATE());

得到的结果和前面的独立查询一样。