当DataTypeCompatility打开时,如何将1899年12月30日参数化为SQL Server本机客户端



短版本

尝试将datetime12/30/1899传递给SQL Server失败,原因是日期格式无效-但仅适用于本机客户端驱动程序,并且仅在DataTypeCompatibility模式下。

长版本

在ADO中尝试使用参数化查询时,针对SQL Server:

SELECT ?

我将datetime值参数化为adDBTimeStamp:

//Language agnostic, vaguely C#-like pseudo-code
void TestIt()
{
DateTime dt = new DateTime("3/15/2020");
VARIANT v = DateTimeToVariant(dt);
Command cmd = new Command();
cmd.CommandText = "SELECT ? AS SomeDate";
cmd.Parameters.Append(cmd.CreateParameter("", adDBTimeStamp, adParamInput, 0, v);

Connection cn = GetConnection();
cmd.Set_ActiveConnection(cn);
cmd.Execute(out recordsAffected, EmptyParam, adExecuteNoRecords);
}

当日期是3/15/2020时,这很好。

创建一个VARIANTVType为7(VT_DATE),值为8字节浮点值:

VARIANT
Int32  vt = 7; //VT_DATE
Double date = 0;

但它在1899年12月30日失败了

如果我用一个特定的日期时间做同样的测试代码,它会失败:

void TestIt()
{
DateTime dt = new DateTime("12/30/1899");
VARIANT v = DateTimeToVariant(dt);
Command cmd = new Command();
cmd.CommandText = "SELECT ? AS SomeDate";
cmd.Parameters.Append(cmd.CreateParameter("", adDBTimeStamp, adParamInput, 0, v);

Connection cn = GetConnection();
cmd.Set_ActiveConnection(cn);
cmd.Execute(out recordsAffected, EmptyParam, adExecuteNoRecords);
}

ADO OLEDB提供程序抛出异常(即在它到达SQL Server之前):

Invalid date format

但并非所有SQL Server OLEDB提供程序都会出现这种情况

在调试这个问题时,我意识到并不是所有的SQL Server OLEDB提供程序都会出现这种情况。Microsoft通常有4个用于SQL Server的OLE DB提供程序:

  • SQLOLEDB:Microsoft OLE DB Provider for SQL Server(自Windows 2000起随Windows提供)
  • SQLNCLI:SQL Server本机客户端(随SQL Server 2005一起提供)
  • SQLNCLI10:SQL Server Native Client 11.0(SQL Server 2008附带)
  • SQLNCLI11:SQL Server Native Client 12.0(随SQL Server 2012一起提供)
  • MSOLEDBSQL:适用于SQL Server的Microsoft OLE DB驱动程序(SQL Server 2016附带)

当与一些不同的提供商一起尝试时,对某些提供商来说效果良好:

  • SQLOLEDB:作品
  • SQLNCLI11(不带DataTypeCompatibility):有效
  • SQLNCLI11(打开DataTypeCompatibility):失败

数据类型兼容性

是的。ActiveX数据对象(ADO)是一个围绕不友好的COM OLEDB API的友好COM包装器,它不理解新的datetimexmldatetime2datetimeoffset数据类型。创建了新的OLEDB数据类型常量来表示这些新类型。因此,任何现有的OLEDB应用程序都不会理解新的常数。

为此,"本地">OLE DB驱动程序:

  • DataTypeCompatibility=80

您可以将其添加到连接字符串中:

"提供者=SQLNCLI11;数据源=螺丝刀;用户ID=hatguy;密码=hunter2DataTypeCompatibility=80";

这指示OLEDB驱动程序仅返回OLEDB首次发明时存在的OLEDB数据类型:

>>td>adLongVarCharadVarWCharadVarBinary(已记录,未测试)adLongVarWChar
SQL Server数据类型SQLOLEDBSQLNCLI1SQLNCLI
(w/DataTypeCompatibility=80)
XmladLongVarWChar141(DBTYPE_Xml)
日期时间adDBTimeStamp
日期时间2adVarWChar
datetimeoffset
日期adVarWChar
时间adVarWChar145(DBTYPE_DBTIME2)
UDT132(DBTYPE_UDT)
varchar(max)adLongVarChar
nvarchar(最大值)adLongVarWChar
varbinary(max)adLongVarBinary
时间戳adBinary
BrakNicku得到了答案。

将参数的NumericScale属性设置为1-7范围内的任何值。

更改代码自:

Parameter p = cmd.CreateParameter("", adDBTimeStamp, adParamInput, 0, v);

Parameter p = cmd.CreateParameter("", adDBTimeStamp, adParamInput, 0, v);
p.NumericScale = 1;

工作。

它甚至可以与针对SQLServer2000的SQLOLEDB驱动程序配合使用。

不同数据类型的精度和规模

从SQL Server返回包含不同数据类型的行集,我可以询问OLEDB各种T-SQL数据类型的PrecisionNumericScale是什么:

SQL Server type   ADO type               Precision  NumericScale  DefinedSize
----------------  ---------------------  ---------  ------------  -----------
int               adInteger (3)          10         255           4
real              adSingle (4)           7          255           4
money             adCurrency (6)         19         255           8
bit               adBoolean (11)         255        255           2
tinyint           adUnsignedTinyInt (17) 3          255           1
bigint            adBigInt (20)          19         255           8
uniqueidentifier  adGUID (72)            255        255           16
char(35)          adChar (129)           255        255           35
nchar(35)         adWChar (130)          255        255           35
decimal(15,5)     adNumeric (131)        15         5             19
datetime          adDBTimeStamp (135)    23         3             16
varchar(35)       adVarChar (200)        255        255           35
text              adLongVarChar (201)    255        255           2147483647
varchar(max)      adLongVarChar (201)    255        255           2147483647
nvarchar(35)      adVarWChar (202)       255        255           35
nvarchar(max)     adLongVarWChar (203)   255        255           1073741823
xml               adLongVarWChar (203)   255        255           1073741823
image             adLongVarBinary (205)  255        255           2147483647
varbinary(max)    adLongVarBinary (205)  255        255           2147483647

由于SQL Server返回的datetime字段的NumericScale3;有可能是改变的美德:

Parameter p = cmd.CreateParameter("", adDBTimeStamp, adParamInput, 0, v);
p.NumericScale = 1;

Parameter p = cmd.CreateParameter("", adDBTimeStamp, adParamInput, 0, v);
p.NumericScale = 3;

奖励阅读

不要试图将datetime参数化为adDBTimestamp。微软的SQL Server OLEDB驱动程序中存在数据丢失错误(全部):

  • SQLOLEDB(1999)-失败
  • SQLNCLI(2005)-失败
  • SQLNCLI10(2008)-失败
  • SQLNCLI11(2010)-失败
  • MSOLEDBSQL(2012)-失败

正确的答案是将所有datetime值参数化为字符串(例如adVarChar);ODBC 24小时格式":

  • yyyy-mm-dd hh:mm:ss.zzz
  • 2021-03-21 18:16:22.619

相关内容

最新更新