You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ODBC Driver 18向Azure SQL插入Timestamp报22008错误求助

问题描述

执行向Azure SQL Server插入Timestamp值时触发错误:

[Microsoft][ODBC Driver 18 for SQL Server]Datetime field overflow. Fractional second precision exceeds the scale specified in the parameter binding. SqlState = 22008

环境信息

  • ODBC驱动:ODBC Driver 18 for SQL Server
  • ODBC版本:3.0(SQL_OV_ODBC3)
  • Azure SQL Server版本:Microsoft SQL Azure (RTM) - 12.0.2000.8
  • 表字段:starttime类型为datetime2(2)(仅支持2位小数秒精度,即百分秒级别)

复现代码

std::string sQuery("insert into DB_TEST.backlog_period (periodid, starttime)  values (?, ?)");
SQLHSTMT hstmt = SQL_NULL_HSTMT;    // Statement handle
SQLRETURN retcode;          // Return status
WCHAR* wsQuery = string_to_whar(sQuery);
// Allocate Statement Handle
retcode = SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc, &hstmt);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
{
    std::cerr << "Error";
    return;
}
SQL_NUMERIC_STRUCT* pOid = new SQL_NUMERIC_STRUCT;
SQL_TIMESTAMP_STRUCT* m_pTimeStamp = new SQL_TIMESTAMP_STRUCT;
size_t nPos = 0;
SYSTEMTIME Time;
GetSystemTime(&Time);
ConvertDoubleToNumericStruct(9999, *pOid);

m_pTimeStamp.year = Time.wYear;
m_pTimeStamp.month = Time.wMonth;
m_pTimeStamp.day = Time.wDay;
m_pTimeStamp.hour = Time.wHour;
m_pTimeStamp.minute = Time.wMinute;
m_pTimeStamp.second = Time.wSecond;
m_pTimeStamp.fraction = Time.wMilliseconds;

SQLWCHAR ColumnName[MAX_COL_NAME_LEN];
SQLSMALLINT    ColumnNameLen;
SQLSMALLINT    ColumnDataType;
SQLULEN        ColumnDataSize;
SQLSMALLINT    ColumnDataDigits;
SQLSMALLINT    ColumnDataNullable;
retcode = SQLPrepare(hstmt, (SQLWCHAR*)wsQuery, SQL_NTSL);

SQLSMALLINT NumParams;
SQLNumParams(hstmt, &NumParams);

retcode = SQLDescribeParam(hstmt,  1, &ColumnDataType, &ColumnDataSize, &ColumnDataDigits, &ColumnDataNullable);
checkAndThrowError(retcode, hstmt, SQL_HANDLE_STMT);
retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_NUMERIC, SQL_NUMERIC, ColumnDataSize, ColumnDataDigits, pOid, sizeof(SQL_NUMERIC_STRUCT), 0);
//above call is equivalent to     
//SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_NUMERIC, SQL_NUMERIC, 10, 0, pOid, sizeof(SQL_NUMERIC_STRUCT), 0);
checkAndThrowError(retcode, hstmt, SQL_HANDLE_STMT);

retcode = SQLDescribeParam(hstmt, 2, &ColumnDataType, &ColumnDataSize, &ColumnDataDigits, &ColumnDataNullable);
checkAndThrowError(retcode, hstmt, SQL_HANDLE_STMT);
retcode = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_TIMESTAMP, SQL_TIMESTAMP, ColumnDataSize, ColumnDataDigits, m_pTimeStamp, sizeof(SQL_TIMESTAMP_STRUCT), 0);
    //above call is equivalent to     
//SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_TIMESTAMP, SQL_TIMESTAMP, 22, 2, m_pTimeStamp, sizeof(SQL_TIMESTAMP_STRUCT), 0);
checkAndThrowError(retcode, hstmt, SQL_HANDLE_STMT);

retcode = SQLExecute(hstmt); // This is getting failed
checkAndThrowError(retcode, hstmt, SQL_HANDLE_STMT);  

问题原因

SQL_TIMESTAMP_STRUCT的fraction字段单位是十亿分之一秒,代码中直接将SYSTEMTIME.wMilliseconds(毫秒,即千分之一秒,数值范围0-999)赋值给它,相当于传递了3位小数的精度,但表字段datetime2(2)仅支持2位小数秒,导致精度溢出触发错误。

解决方案

方案1:调整fraction值适配字段精度

将毫秒转换为2位精度的十亿分之一秒,修改赋值代码:

// 将毫秒转为百分秒(保留2位精度),再转换为十亿分之一秒
m_pTimeStamp.fraction = (Time.wMilliseconds / 10) * 10000000;

或者通过算术运算截断第三位:

m_pTimeStamp.fraction = (Time.wMilliseconds * 1000000) / 10;

方案2:修改表字段精度

如果业务允许毫秒级精度,将starttime字段类型改为datetime2(3),可直接兼容毫秒值,无需修改代码。

方案3:显式指定绑定参数的scale

在SQLBindParameter调用时,显式指定scale为2,确保和表字段精度匹配:

retcode = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_TIMESTAMP, SQL_TIMESTAMP, 22, 2, m_pTimeStamp, sizeof(SQL_TIMESTAMP_STRUCT), 0);

内容的提问来源于stack exchange,提问作者Rakesh Mehta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 18:39:58