【问题标题】:dbFailOnError SQL Server datetime bug for time-only values仅时间值的 dbFailOnError SQL Server 日期时间错误
【发布时间】:2017-01-11 05:16:29
【问题描述】:

我在 SQL Server 中有一个链接表,其中包含一个日期时间列,我在其中存储了一个仅限时间的值*。如果我在没有 dbFailOnError 的情况下执行 UPDATE 查询,它会将该命令转换为 SELECT,然后是一次执行一行的单个 UPDATE 语句:

exec sp_executesql N'UPDATE "dbo"."Appeals" SET "HearingTime"=@P1 
                     WHERE "AppealID" = @P2'
                  ,N'@P1 datetime,@P2 int','1899-12-30 09:00:00',1
...
exec sp_executesql N'UPDATE "dbo"."Appeals" SET "HearingTime"=@P1 
                     WHERE "AppealID" = @P2'
                  ,N'@P1 datetime,@P2 int','1899-12-30 09:00:00',4

如果我执行完全相同的 UPDATE 查询,但使用 dbFailOnError,我会得到以下翻译:

UPDATE "dbo"."Appeals" SET HearingTime={t '09:00:00'} 

有趣的是,dbFailOnError 会在后端强制执行更高效的 UPDATE,但我真正关心的是时间值本身。

在第一个示例中,Access 正确地将日期时间设置为 12/30/1899(MS Access 的神奇“零”日)。在第二种情况下,这不会发生。最终结果是第一个示例“有效”,而第二个示例无效。

我的意思是,如果我在数据表视图中查看 HearingTime 字段,Access 会将第一个字段显示为:

9:00:00 AM

第二个显示为(截至撰写本文时,9/3/16 是今天的日期):

9/3/2016 9:00:00 AM

我不得不假设这是微软的一个错误。或者我在这里错过了什么?我是否有比报告错误并希望微软有朝一日修复它更好的选择?


*是的,我知道 SQL Server 中有 time 数据类型。它与 MS Access 日期时间类型不兼容,因此在 MS Access 链接表中对我来说几乎没有用处。

【问题讨论】:

  • 您使用的是哪个 ODBC 驱动程序?你试过不同的吗?哪个版本的 SQL Server?
  • 我正在使用 {SQL Server} 驱动程序 (SQLSRV32.dll)。但是我在使用 {SQL Server Native Client 11.0} (SQLNCLI11.dll) 和 {SQL Server Native Client 10.0} (SQLNCLI10.dll) 时得到了相同的行为。我也使用 {ODBC Driver 11 for SQL Server} (MSODBCSQL11.dll) 和 {ODBC Driver 13 for SQL Server} (MSODBCSQL13.dll) 得到相同的行为。

标签: sql-server datetime ms-access defects


【解决方案1】:

我能够使用带有 Access SQL 日期/时间文字的查询重现您的问题。两者都有

Dim cdb As DAO.Database
Set cdb = CurrentDb
cdb.Execute "UPDATE dbo_Appeals SET HearingTime=#10:00:00#", dbFailOnError

Dim cdb As DAO.Database
Set cdb = CurrentDb
cdb.Execute "UPDATE dbo_Appeals SET HearingTime=#1899-12-30 11:00:00#", dbFailOnError

导致 [HearingTime] 值使用当前日期 (2016-09-03),而不是“零”日期。

但是,将完整的日期/时间作为 字符串 似乎可以工作

Dim cdb As DAO.Database
Set cdb = CurrentDb
cdb.Execute "UPDATE dbo_Appeals SET HearingTime='1899-12-30 12:00:00'", dbFailOnError

(省略字符串值中的日期部分会导致 SQL Server DATETIME“零”日期为 1900-01-01 的 [HearingTime] 值。)

而且,更好的是,带有DAO.QueryDef 对象的参数化查询似乎也可以正常工作

Dim cdb As DAO.Database
Set cdb = CurrentDb
Dim qdf As DAO.QueryDef
Set qdf = cdb.CreateQueryDef("", _
        "PARAMETERS prmHearingTime DateTime;" & _
        "UPDATE dbo_Appeals SET HearingTime=[prmHearingTime]")
qdf!prmHearingTime = #10:00:00 AM#
qdf.Execute dbFailOnError

【讨论】:

  • 是的,string 表示似乎有效。很有趣。
  • 此解决方法似乎也适用于本地 Jet/ACE 表。因此,它应该足够安全,可以用作任何 Jet/ACE/SQL Server 表的通用解决方法。它也可能适用于其他后端,例如 MySQL 或 PostgreSQL,但我没有测试任何这些。
【解决方案2】:

这是一个好问题,我可以重现它。

这似乎是 ODBC 驱动程序中的一个错误,因为您演示的行为是 ODBC 驱动程序应该补偿的 SQL Server 行为,就像在您的第一个示例中通过提供将转换的完整日期时间字符串一样在 Access 中回读时正确。

除了在您回读数据时将 TimeValue 应用于日期时间值之外,我看不出有任何解决办法。但是,这将停止使用您的时间字段的索引。

SQL Server 的数据类型 Time 不能用于许多事情,因为 ODBC 驱动程序将这些作为文本读取。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-01
    • 2017-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-19
    • 1970-01-01
    相关资源
    最近更新 更多