SQL Datetime / datetimeoffset(2) 比较和隐式转换

Sim*_*hes 6 sql-server

我在我们的数据库中插入数据时发现了一个问题。我的插入语句正在检查 WHERE 子句中是否存在数据以防止插入重复数据。没有检测到,并且 INSERT 发生了。但是,唯一约束拒绝了数据,因为它已经存在于数据库中。

问题是要插入的数据是 DATETIMEOFFSET(2),插入的数据库字段是 DATETIME。

为了表明你想要我正在谈论,运行以下命令:

DECLARE @dt  DATETIME          = '2014-07-07 09:49:33.000';
DECLARE @dto DATETIMEOFFSET(2) = '2014-07-07 09:49:33.00 +07:00';

PRINT CASE WHEN @dt = @dto THEN 'Equals matches'
           ELSE 'Equals does not match'
      END

PRINT CASE WHEN @dt = CAST(@dto AS DATETIME) THEN 'Cast matches'
           ELSE 'Cast does not match'
      END
Run Code Online (Sandbox Code Playgroud)

它打印:

  • 等于不匹配
  • 投射比赛

如果插入数据,比较 (=) 运算符的执行方式与隐式强制转换的执行方式不同。cast/convert 运算符实际上丢弃了偏移量!疯狂。

为什么比较运算符的工作方式与 INSERT 期间发生的隐式转换不同?

sou*_*lex 9

看起来相反是正确的:隐式转换将偏移量带入方程,但转换/转换函数没有。

DECLARE @dt  DATETIME          = '2014-07-07 02:49:33.000';
DECLARE @dto DATETIMEOFFSET(2) = '2014-07-07 09:49:33.000 +07:00';

PRINT CASE WHEN @dt = @dto THEN 'Equals matches'
           ELSE 'Equals does not match'
      END

PRINT CASE WHEN @dt = CAST(@dto AS DATETIME) THEN 'Cast matches'
           ELSE 'Cast does not match'
      END

PRINT CASE WHEN @dt = CONVERT(DATETIME,@dto) THEN 'Convert matches'
           ELSE 'Convert does not match'
      END    
Run Code Online (Sandbox Code Playgroud)

比较这个(从@dt 减去 7 小时)结果:

  • 等于匹配
  • 演员表不匹配
  • 转换不匹配

做了一些更多的调查,并偶然发现了这篇文章。

“当您从 datetime2 或 datetimeoffset 转换为 date 时,没有舍入并且日期部分被显式提取。对于从 datetimeoffset 到 date、time、datetime2、datetime 或 smalldatetime 的任何隐式转换,转换基于本地日期和时间价值。”

因此,当您想将 '2014-07-07 09:49:33.000' 和 '2014-07-07 09:49:33.000 +07:00' 视为相等时,您唯一的选择是通过强制转换或转变。由于隐式转换仅在您服务器的时区偏移量恰好与@dto 中指定的偏移量相同时才有效。