According to cdonner, in his answer here and on his blog.
He claims that BETWEEN with date yields inconsistent results
From his blog:
<I have to use something like this:
Declare @BeginDate SmallDateTime
Declare @EndDate SmallDateTime
Set @BeginDate = '2007-08-01'
Set @EndDate = '2007-08-31'
Select *
From dbo.table1 a
Where a.session_date Between @BeginDate + ' 00:00:00' And @EndDate + ' 23:59:59'
Order By a.session_date asc
To get correct BETWEEN datetime's
SQL server stores datetime values as a number. For instance, 0 is 1900-01-01 00:00:00.000
The example you give in your question is subject to rounding problems, similar to how the floating-point value 1.0 is stored as 0.99999...
To accurately compare dates, you would cast the value to a datetime type and then do your comparison.
SELECT
CASE
WHEN cast('1/1/08' as datetime)
BETWEEN cast('1/1/08' as datetime) AND cast('2/1/08' as datetime)
THEN 'in' ELSE 'out'
END AS s1,
CASE
WHEN cast('1/1/08' as datetime)
BETWEEN cast('12/31/07' as datetime) AND cast('1/1/08' as datetime)
THEN 'in' ELSE 'out'
END AS s2
Which will result in your expected output: s1==in, s2==in
In Oracle:
select
case when '1/1/08' between '1/1/08' and '2/1/08'
then 'in' else 'out' end as s1,
case when '1/1/08' between '12/31/07' and '1/1/08'
then 'in' else 'out' end as s2
FROM dual
in out
You are comparing strings here, not dates.
There is nothing BETWEEN
12/31/07 and 1/1/08
, as 2
goes after /
in ASCII
Just never ever use BETWEEN with datetime values. In MySQL I can do
created >= CURDATE() - INTERVAL 1 DAY AND created < CURDATE()
to limit created to (the whole of) yesterday.
With BETWEEN '2011-05-02' AND '2011-05-02 23:59:59' I would be gambling on one-second resolution, and would miss a created of '2011-05-02 23:59:59.001'.
Because he's totally wrong - it's comparing strings
if you cast them to a datetime or replace them with date variables it works:
select
case when CAST('JAN 01 2008' as smalldatetime)
between CAST('JAN 01 2008' as smalldatetime)
and CAST('FEB 01 2008' as smalldatetime)
then 'in' else 'out' end as s1,
case when CAST('JAN 01 2008' as smalldatetime)
between CAST('DEC 31 2007' as smalldatetime)
and CAST('JAN 01 2008' as smalldatetime)
then 'in' else 'out' end as s2
The code on the blog was nonsense, and I owe Mark for pointing that out to me. The issue exists. It has nothing to do with BETWEEN, but with rounding (which can cause BETWEEN to fail in certain circumstances). While SQL Server does round, .Net does not, and I ran into issues with multiple inserts in a very short timeframe where I assumed that I had distinct datetime values, but due to rounding they became the same in the database. The post was corrected a long time ago, and the code examples still work on SQL Server 2008.
If you run this query, you will see what I was referring to:
select convert(varchar(32), convert(datetime,
'9/1/08 00:00:00.005'), 121);