gpt4 book ai didi

c++ - 如何使用新的 SQL Server Native Client 将 datetime 迁移到 datetime2

转载 作者:太空狗 更新时间:2023-10-29 21:39:53 24 4
gpt4 key购买 nike

我们目前正在将数据库从 datetime 迁移到 datetime2,包括 SQL Server Native Client v11 (SQL Server 2012)。数据库更新很容易完成,但随着我们要使用的新 SQL Server Native Client 11 出现问题。

一般来说,我们的 OLE DB 消费者具有“COLUMN_ENTRY*”访问器,用于我们的 CRUD 操作。对于 datetime2 列,成员的类型为 DBTIMESTAMP。使用 SQLNCLI 提供程序,DBTIMESTAMP 的小数部分被静默截断为支持的值。在 SQLNCLI11 中,带有太精确分数的插入会导致此错误:

DB_E_ERRORSOCCURRED 多步 OLE DB 操作产生错误。检查每个 OLE DB 状态值(如果可用)。没有完成任何工作。

根据 this link , 如果向字段中插入了太多数据,则会返回此错误。由此我假设 DBDATETIME 成员的小数部分过于精确而无法插入。根据this link ,新的 Native Client 版本(10 和 11)不会截断但会因错误而失败。以我们想要实现的这个简化示例为例:

class CMyTableStruct
{
public:
CMyTableStruct();
LONG m_lID;
DBTIMESTAMP m_dtLogTime;
};
class CMyTableStruct_InsertAccessor : public CMyTableStruct
{
public:
BEGIN_PARAM_MAP(CMyTableStruct_InsertAccessor)
COLUMN_ENTRY(1, m_dtLogTime)
END_PARAM_MAP()
};

在代码的某些部分,我将时间戳初始化为 2015-08-10 07:47:49.986149999 并且插入失败。如果我将分数重置为 0,则插入有效; 0 旁边的任何值都失败。我尝试使用具有各种值的 COLUMN_ENTRY_PS 提供日期时间精度和比例,但插入总是失败。

我们如何强制 Native Client 简单地接受值并截断它?很明显,我们无法手动将所有值截断为支持的数据库精度。我找不到任何关于如何将 datetime2 与新的 Native Client 一起使用的适当文档。我们是否缺少任何正确处理 datetime2 的转换或设置?

这是测试设置:

  • Windows 7 64 位
  • SQL Server native 客户端 11 (SQLNCLI11)
  • SQL Server 2012
  • DBPROP_INIT_LCID=2055
  • DBPROP_INIT_PROMPT=4
  • DBPROP_INIT_DATASOURCE=localhost
  • DBPROP_AUTH_INTEGRATED=SSPI

使用 SQLNCLI 提供程序可以使用相同的代码。

[编辑#1]:我使用 AtlTraceErrorRecords 转储了更多错误信息,这证实了与链接的 Microsoft Connect 报告中相同的错误:

行号:0 来源:“Microsoft SQL Server Native Client 11.0” 描述:“提供的时间值的小数部分溢出相应 SQL Server 参数或列的小数位数。增加 DBPARAMBINDINFO 或列小数位数中的 bScale来纠正这个错误。”帮助文件:“(空)”帮助上下文:0 GUID:{0C733A63-2A1C-11CE-ADE5-00AA0044773D}

[编辑#2]:根据我的进一步研究,这似乎是新 Native Client 定义和接受的行为。参见 Stricter SQL_C_TYPE _TIMESTAMP and DBTYPE_DBTIMESTAMP parameter validation以供引用。但是,如果没有任何有关如何正确使用 datetime2 的文档,Microsoft 将无法认真对待此更改。在将它们插入数据库之前,他们真的需要开发人员自己对 DBTIMESTAMP 进行舍入吗?在某些情况下,由于某些浮点精度错误,四舍五入甚至不起作用。以上面的示例时间戳为例,您将看到典型的 .9999 精度错误。有人应该如何让这种奇怪的行为起作用?对于此错误消息,如果不使用 now() 的 SQL 函数,您甚至无法将当前时间戳保存到数据库中,因为您通常会在这些溢出中运行。

最佳答案

我做了一些测试并完全重写了我的答案。

我使用带有 Native Client 10 的 SQL Server 2008。它已经支持 datetime2(7),所以我的测试是适用的。

日期时间

我有一个具有表值参数的存储过程。参数表的其中一列具有 datetime 类型。我之前没有使用非零分之一秒,但现在尝试了。我花了一段时间才弄清楚需要什么。

为了在 DBTIMESTAMP.fraction 字段中使用非零值,我必须配置列描述和参数描述:将 DBCOLUMNDESC.bScale 设置为 3 和 DBBINDING.bScale 为 3。bPrecision 都保留为 0。这个 MSDN doc 帮助我意识到我还必须设置 DBCOLUMNDESC.bScale

The SQL Server Native Client OLE DB provider inspects the DBCOLUMDESC bScale member to determine the fractional seconds precision.

一旦 Scale 设置为 3,我就可以将 DBTIMESTAMP.fraction 的值设置为 555000000 并且它被成功插入到数据库中.557,即服务器将值进一步四舍五入到毫秒的 1/3(datetime 类型的精度)。 但是,当我尝试将 DBTIMESTAMP.fraction 的值设置为 552100000 时,我遇到了与您遇到的相同的错误。因此,服务器希望程序员自己对值进行舍入。

截断分数的一种简单方法是这样的:

DBTIMESTAMP dt;
// set to any value from 0 to 999,999,999 (billionth of a second)
dt.fraction = 555123456;

// truncate fractions to milliseconds before inserting into the database
dt.fraction /= 1000000;
dt.fraction *= 1000000;

datetime2(7)

我将表值参数中的列类型更改为 datetime2(7) 并做了更多测试。

我将 Scale 设置为 7,并且可以成功地将值 555123400 插入到数据库 DBTIMESTAMP.fraction 中,但是当我尝试插入时值 555123478 我得到了同样的错误。因此,对于 datetime2(7),服务器还希望程序员自己对值进行舍入。

// truncate fractions to 100 nanoseconds precision
dt.fraction /= 100;
dt.fraction *= 100;

应该够了。

关于c++ - 如何使用新的 SQL Server Native Client 将 datetime 迁移到 datetime2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31915308/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com