为什么sql日期比较返回0结果

为什么sql日期比较返回0结果,sql,linq-to-sql,sql-server-2008,Sql,Linq To Sql,Sql Server 2008,如果这个问题太长,我提前表示歉意,但我想确保我包括了达到这一点所遵循的所有步骤 我的SQL Server 2008数据库中有下表: CREATE TABLE [VSPRRecalc]( [VSPRDate] [datetimeoffset](7) NOT NULL, [CalcType] [int] NOT NULL, CONSTRAINT [PK_VSPRRecalc] PRIMARY KEY CLUSTERED ([VSPRDate] ASC) 其中的一些行如下所示: IN

如果这个问题太长,我提前表示歉意,但我想确保我包括了达到这一点所遵循的所有步骤

我的SQL Server 2008数据库中有下表:

CREATE TABLE [VSPRRecalc](
    [VSPRDate] [datetimeoffset](7) NOT NULL,
    [CalcType] [int] NOT NULL,
CONSTRAINT [PK_VSPRRecalc] PRIMARY KEY CLUSTERED ([VSPRDate] ASC)
其中的一些行如下所示:

INSERT [vsprrecalc](VSPRDate,CalcType) VALUES('2010-12-15 10:17:49.5780000 -05:00','3')
INSERT [vsprrecalc](VSPRDate,CalcType) VALUES('2010-12-16 07:44:03.3750000 -05:00','1')
INSERT [vsprrecalc](VSPRDate,CalcType) VALUES('2010-12-17 07:40:40.1090000 -05:00','1')
INSERT [vsprrecalc](VSPRDate,CalcType) VALUES('2010-12-18 16:29:02.2203744 -05:00','2')
INSERT [vsprrecalc](VSPRDate,CalcType) VALUES('2010-12-20 09:58:50.1250000 -05:00','1')
INSERT [vsprrecalc](VSPRDate,CalcType) VALUES('2010-12-29 19:21:26.8120000 -05:00','1')
我使用linq检查并查看此表中是否已经存在给定日期:

var recalc = (from re in VSPRRecalcs
              where re.VSPRDate.Date == oDate.Value.Date
              select re).SingleOrDefault();
当前,
recalc
每当日期在午夜5小时内时返回null(如上面insert语句中的12-29)。我已检查,正在执行以下sql:

exec sp_executesql N'SELECT [t0].[VSPRDate], [t0].[CalcType]
                     FROM [dbo].[VSPRRecalc] AS [t0]
                     WHERE 
                     CONVERT(DATE, [t0].[VSPRDate]) = @p0',N'@p0 datetime',@p0='2010-12-29'
返回0条记录。我修改了查询以使测试更易于操作,并得出以下结论:

declare @t as date
set @t =  '2010-12-29'

select *, 
case  when  CONVERT(DATE, [VSPRDate]) = @t then 'true' else 'false' end  
from VSPRRecalc where 
CONVERT(DATE, [VSPRDate]) = @t 

该查询适用于表中的任何其他日期,但不适用于午夜5小时内的任何日期(再次参见上文12-29)。如果我在没有where子句的情况下运行上述查询,那么12-29行的“true”显示得非常清楚,布尔值正在以我在
select
语句中期望的方式进行计算,而不是在
where
子句中。为什么会发生这种情况?

我想说,这是SQL Server上的一个错误,关于
DATETIMEOFFSET
time和更“标准”的类型
DATETIME
DATE
之间的转换

我发现的情况如下:

declare @t as date
set @t =  '2010-12-29'

select *, 
case  when  CONVERT(DATE, [VSPRDate]) = @t then 'true' else 'false' end  
from VSPRRecalc where 
CONVERT(DATE, [VSPRDate]) = @t 
这个有效:

EXEC sp_executesql N'SELECT [t0].[VSPRDate], [t0].[CalcType]
                     FROM [dbo].[VSPRRecalc] AS [t0]
                     WHERE [t0].[VSPRDate] = @p0',

                     N'@p0 DATETIMEOFFSET(7)',
                     @p0 = '2010-12-29 19:21:26.8120000 -05:00'
这意味着当我们继续使用
DATETIMEOFFSET
时,没有任何问题。。。不过,您似乎需要查找给定日期内的所有记录,而不是搜索确切的
DATETIMEOFFSET
,对吗

因此,可能更有用一点,这个也可以:

EXEC sp_executesql N'SELECT [t0].[VSPRDate], [t0].[CalcType]
                 FROM [dbo].[VSPRRecalc] AS [t0]
                 WHERE [t0].[VSPRDate] BETWEEN @p0 AND @p1',

                 N'@p0 DATETIMEOFFSET, @p1 DATETIMEOFFSET',
                 @p0 = '2010-12-29 00:00:00.0000000 -05:00',
                 @p1 = '2010-12-30 00:00:00.0000000 -05:00'
我想这里的秘密是继续使用
DATETIMEOFFSET
数据类型(它是CLR等价物)。这样你就不会陷入这个转换问题

(顺便说一句,您应该使用
BETWEEN
来根据日期搜索记录。这允许DBMS在该列上使用索引,这在
WHERE
子句进行函数调用或硬编码转换时是不可能的)


编辑我忘了Linq for SQL没有可用的
BETWEEN
操作符-但这很容易修复,只需使用
WHERE[t0].[VSPRDate]>=@p0和[t0].[VSPRDate]之类的东西,我想说这是SQL Server上的一个bug,关于
DATETIMEOFFSET
时间和更“标准”时间之间的转换类型
DATETIME
DATE

我发现的情况如下:

declare @t as date
set @t =  '2010-12-29'

select *, 
case  when  CONVERT(DATE, [VSPRDate]) = @t then 'true' else 'false' end  
from VSPRRecalc where 
CONVERT(DATE, [VSPRDate]) = @t 
这个有效:

EXEC sp_executesql N'SELECT [t0].[VSPRDate], [t0].[CalcType]
                     FROM [dbo].[VSPRRecalc] AS [t0]
                     WHERE [t0].[VSPRDate] = @p0',

                     N'@p0 DATETIMEOFFSET(7)',
                     @p0 = '2010-12-29 19:21:26.8120000 -05:00'
这意味着当我们继续使用
DATETIMEOFFSET
时,没有任何问题。。。不过,您似乎需要查找给定日期内的所有记录,而不是搜索确切的
DATETIMEOFFSET
,对吗

因此,可能更有用一点,这个也可以:

EXEC sp_executesql N'SELECT [t0].[VSPRDate], [t0].[CalcType]
                 FROM [dbo].[VSPRRecalc] AS [t0]
                 WHERE [t0].[VSPRDate] BETWEEN @p0 AND @p1',

                 N'@p0 DATETIMEOFFSET, @p1 DATETIMEOFFSET',
                 @p0 = '2010-12-29 00:00:00.0000000 -05:00',
                 @p1 = '2010-12-30 00:00:00.0000000 -05:00'
我想这里的秘密是继续使用
DATETIMEOFFSET
数据类型(它是CLR等价物)。这样你就不会陷入这个转换问题

(顺便说一句,您应该使用
BETWEEN
来根据日期搜索记录。这允许DBMS在该列上使用索引,这在
WHERE
子句进行函数调用或硬编码转换时是不可能的)


Edit我忘了Linq for SQL没有可用的
BETWEEN
操作符-但这很容易修复,只需使用
WHERE[t0].[VSPRDate]>=@p0和[t0].[VSPRDate]奇怪,上面的
executesql
语句对我有效(它返回1行)。。。。。。但是,事实上,您上面的最后一句话对我也不起作用(对于2010-12-29行,
case
表达式返回
true
,但是如果我包括where部分,则不返回任何行)!很抱歉,执行sql语句是我正在进行的一些测试遗留下来的。我现在对它进行了编辑,以反映应该出现的内容。如果包含
和VSPRDate='2010-12-29 19:21:26.8120000-05:00'
查询确实有效。我不知道区别是什么。不要忘记SqlMethods类,它允许您在数据库上运行DateDiffDay(start,finish)==0之类的SQL函数。奇怪的是,上面的
executesql
语句适合我(它返回1行)。。。。。。但是,事实上,您上面的最后一句话对我也不起作用(对于2010-12-29行,
case
表达式返回
true
,但是如果我包括where部分,则不返回任何行)!很抱歉,执行sql语句是我正在进行的一些测试遗留下来的。我现在对它进行了编辑,以反映应该出现的内容。如果包含
和VSPRDate='2010-12-29 19:21:26.8120000-05:00'
查询确实有效。我不知道区别是什么。不要忘记SqlMethods类,它允许您在数据库上运行DateDiffDay(start,finish)==0之类的SQL函数。我将Linq更改为
VSPRDate>=oDate.Date&&VSPRDate
。这似乎有效。我将Linq更改为
VSPRDate>=oDate.Date&&VSPRDate
。这似乎奏效了。