SQL日期比较仅使用日期而不是时间

时间:2010-07-27 15:57:01

标签: sql sql-server tsql date-comparison

这原本是一个关于如何实现这个问题的问题,因为我被困在某一部分,但我现在很好奇为什么这首先发生了。如果时间没有差异,我只需要比较日期而不是时间,这不是问题。下面的代码显示了我最初尝试的查询

SELECT *
FROM Employee e
inner join OT_Hours o on o.Emp_ID=e.Emp_ID
inner join Position p on p.Position_ID=e.Position_ID
inner join Signup_Sheet s on s.Employee_ID=e.Emp_ID
WHERE e.Eligible_OT=1 and s.Day_Shift = 1 
and p.Position_Name = 'Controller' 
and Convert(Varchar(20),s.Date,101) = '07/26/2010'
and Convert(Varchar(20),o.Date,101) <='07/26/2010'
and Convert(Varchar(20),o.Date,101) > '07/26/2009'
and o.Quantity NOT IN(0.3) order by o.Date DESC

当我运行该查询时,我没有得到任何结果,但当我删除第二行后,它将返回12个结果(&lt; =),当我删除第3个最后一行但保留第二个最后一行时,它将返回6个结果(大于)。在查看数据后,我可以看到应该返回其中4个结果。现在为了奇怪的部分。以下是我目前使用的代码。

SELECT DISTINCT o.Date, e.Emp_ID as Emp_ID, e.First_Name+ ' ' +e.Last_Name as Name, o.Quantity as Sum
FROM Employee e
left join OT_Hours o on o.Emp_ID=e.Emp_ID
left join Position p on p.Position_ID=e.Position_ID
left join Signup_Sheet s on s.Employee_ID=e.Emp_ID
WHERE e.Eligible_OT=1 and s.Day_Shift = 1 
and p.Position_Name = 'Controller' 
and Convert(Varchar(20),s.Date,101) = '07/26/2010'
and o.Date between '07/26/2009' and '07/26/2010'
and o.Quantity NOT IN(0.3) order by o.Date DESC

此查询将返回结果,但我也测试了它,就像我在o.Date高于和低于指定日期时做的另一个。当日期为&lt; = 16时,返回结果,当&gt;返回了8个结果。最终查询产生了6个结果。现在这不是我要查询的生产数据库,我是唯一一个使用它的数据,所以数据没有改变。有关为何发生这种情况的任何解释?我假设它与将其转换为varchar有关,但它无法正确比较,但这并不能解释为什么我会得到12&lt; =,6&gt;然后没有结果。如果有人知道更好的方法来实现这一点,请告诉我。

6 个答案:

答案 0 :(得分:7)

两个查询不一样 - 这个:

and o.Date between '07/26/2009' and '07/26/2010'

......相当于:

and o.Date >= '07/26/2009' 
and o.Date <= '07/26/2010'

BETWEEN是ANSI标准,包含在我遇到过的每个数据库中。

请注意,如果您没有为DATETIME指定时间部分,则该值默认为从当天午夜00:00:00开始。

答案 1 :(得分:5)

我从2007年2月的SQL Server杂志(Itzik Ben-Gan的日期时间计算)中学到了这种技术。这样,无论行的日期是否在午夜之后,你的'之间'都会起作用,因为所有事情都已经标准化为午夜进行比较:

select *
from someTable
where dateadd(day, datediff(day, 0, somedate), 0) between '07/26/2009' and '07/26/2010' 

dateiff和dateadd一起工作以剥离时间并离开日期。然后,您可以将其与字符串文字或已完成相同修改的其他日期进行比较。我建议把它放在一个函数中。

编辑: 基于OMG小马的评论。这不会利用日期列上的索引。除了其他人提到的技术之外,另一种方法可能是使用时间剥离技术。因此,不要在表的列上执行此操作,而是在“between”的最后一个参数上执行此操作。你可以有这样的功能:

CREATE FUNCTION [dbo].[fn_enddate](@enddate datetime)
RETURNS datetime AS  
BEGIN
    DECLARE @endOfDay datetime
    set @endOfDay = dateadd(millisecond, -2, dateadd(day, datediff(day, 0, @enddate) + 1, 0))
    return @endOfDay
END

这将获取参数日期,将其设置为第二天的午夜,然后减去两毫秒,给出给定日期时间的结束日期。那么你可以这样做:

select *
from someTable
where somedate between '07/26/2009' and dbo.fn_enddate('07/26/2010')

答案 2 :(得分:4)

在第一个查询的最后一行的第三行中,您将比较两个字符串。

因此01/02/2009大于01/01/2010

我通常约会BETWEEN '01/02/2009 00:00:00.000' AND '01/01/2010 23:59:59.997',但看到更好的解决方案会很有趣。

答案 3 :(得分:1)

如果您的数据库是SQL Server,我所做的工作很好,剥离时间就像下面这样....

SELECT DISTINCT o.Date, e.Emp_ID as Emp_ID, e.First_Name+ ' ' +e.Last_Name as Name, o.Quantity as Sum 
FROM Employee e 
left join OT_Hours o on o.Emp_ID=e.Emp_ID 
left join Position p on p.Position_ID=e.Position_ID 
left join Signup_Sheet s on s.Employee_ID=e.Emp_ID 
WHERE e.Eligible_OT=1 and s.Day_Shift = 1  
and p.Position_Name = 'Controller'  
and CAST(FLOOR(CAST(s.Date AS FLOAT)) AS DATETIME) = '07/26/2010' 
and CAST(FLOOR(CAST(o.Date AS FLOAT)) AS DATETIME) between '07/26/2009' and '07/26/2010' 
and o.Quantity NOT IN(0.3) order by o.Date DESC 

根据您的参数设置'07 / 26/2010','07 / 26/2009',您可以将它们存储在日期时间变量中并执行相同的cast(floor(cast(@datevar as float)) as datetime)操作。

这似乎是一个转贴。在此处查看已接受的答案... How to remove the time portion of a datetime value (SQL Server)?

答案 4 :(得分:1)

...
AND s.Date BETWEEN '2010-07-26 00:00:00.000' AND '2010-07-26 23:59:59.997'
AND o.Date BETWEEN '2009-07-26 00:00:00.000' AND '2010-07-26 23:59:59.997'
...

答案 5 :(得分:1)

我的建议是调整您的标准以涵盖时间,而不是日期本身。如果转换或以其他方式操作比较列,则可以破坏查询中索引的使用。

此外,始终将日期与日期进行比较。当你将它们转换为字符串并尝试比较时,你会遇到问题,正如Chris Diver指出的那样。

在你的情况下,我会尝试:

SELECT
    o.Date,
    e.Emp_ID as Emp_ID,
    e.First_Name+ ' ' +e.Last_Name as Name,
    o.Quantity as Sum
FROM
    Employee e
LEFT JOIN OT_Hours o ON o.Emp_ID = e.Emp_ID
LEFT JOIN Position p ON p.Position_ID = e.Position_ID
LEFT JOIN Signup_Sheet s ON s.Employee_ID = e.Emp_ID
WHERE
    e.Eligible_OT = 1 AND
    s.Day_Shift = 1 AND
    p.Position_Name = 'Controller' AND
    (s.Date >= @signup_date AND s.Date < DATEADD(dy, 1, @signup_date)) AND
    (o.Date >= @order_start_date AND o.Date < DATEADD(dy, 1, @order_end_date)) AND
    o.Quantity NOT IN (0.3)
ORDER BY
    o.Date DESC

您需要确保参数或变量始终没有时间部分。