如何从 VBA ADODB 中的参数化 SQL 服务器查询诊断语法错误
How to diagnose syntax error from a parameterized SQL Server query in VBA ADODB
我正在使用 VBA adodb 根据 Excel 行内容在 SQL 服务器中编写 INSERT
语句。
我正在使用参数化查询,所以我的 VBA 代码具有以下形式:
sqlStatement = "INSERT INTO dbo.mytable (" & Join(insertElement(0), ", ") & ") VALUES (" & Join(insertElement(2), ", ") & ")"
Set cm = New ADODB.Command
With cm
Debug.Print (sqlStatement)
.ActiveConnection = conn
.CommandText = sqlStatement
.CommandType = adCmdText
For Each e In insertElement(1)
Set Pm = .CreateParameter(, adVarChar, 3, 1024, e)
.Parameters.Append Pm
Next e
Set rs = .Execute
End With
其中 insertElement(0)
是字段名称数组,...(1) 是值数组,...(2) 是占位符数组 ?
支持参数化
当我运行这段代码时,我得到一个错误
[Microsoft][ODBC Driver 13 for SQL Server][SQL Server] Incorrect syntax near 'Output'
然而,当我查询sqlStatement
文本时,语句中的任何地方都没有'Output'。文本格式为:
INSERT INTO dbo.mytable ([my_field_1],[my_field_2],[somefieldshaveweirdcharslike+#], ...) VALUES (?, ?, ?, ...)
所以,如果我不直接提供 'Output' 命令,而且我无法直接看到该语句,因为它是在服务器端处理的,我该如何诊断语法?
您应该能够通过迭代您的数组并以您认为合适的方式连接您的值来简单地构建您的 SQL 语句,而不是试图将一堆参数插入一堆问号中。像这样的东西(我假设 insertElement
实际上是一个二维数组而不是一个集合;如果它真的是一个集合那么你需要做一些与 For Each
类似的事情):
sqlStatement = "INSERT INTO dbo.mytable (" & Join(insertElement(0), ", ") & ") VALUES ("
Set cm = New ADODB.Command
With cm
.ActiveConnection = conn
.CommandType = adCmdText
Dim aCount As Integer
aCount = Ubound(insertElement(1))
For i = 0 To aCount - 1
sqlStatement = sqlStatement & "'" & insertElement(1,i) & "'" & _
Iif(i <> aCount - 1, ",", "")
Next
.CommandText = sqlStatement
Set rs = .Execute
End With
综上所述,如果您想更深入地了解错误发生的位置,您可以尝试迭代 Connection
对象的 Errors collection。由于尝试使用连接会产生多个错误,因此仅使用 Err
对象进行故障排除可能有点困难。
最后,最好在服务器端的存储过程中设置您的 INSERT
语句,并以这种方式将值作为参数传递,除非您没有理由担心注入攻击。
我在 SQL 服务器中没有跟踪权限,因此我探索服务器端日志记录的选项有限。
我最终以蛮力方式解决了这个问题,一次添加一个字段,直到我收到错误。
就我而言,根本问题与将 adodb adNumeric
参数类型用于十进制值有关。我将参数类型切换为 adDecimal
,然后在各个参数对象上设置 NumericScale
和 Precision
值。 vba 代码结构如下所示
For Each p In paramArr
If p(1) = adVarChar Then
Set Pm = .CreateParameter(, p(1), 1, Len(p(2)), p(2))
Else
Set Pm = .CreateParameter(, p(1), 1, , p(2))
End If
If p(1) = adDecimal Then
Pm.NumericScale = 3
Pm.Precision = 13
End If
.Parameters.Append Pm
Next p
我正在使用 VBA adodb 根据 Excel 行内容在 SQL 服务器中编写 INSERT
语句。
我正在使用参数化查询,所以我的 VBA 代码具有以下形式:
sqlStatement = "INSERT INTO dbo.mytable (" & Join(insertElement(0), ", ") & ") VALUES (" & Join(insertElement(2), ", ") & ")"
Set cm = New ADODB.Command
With cm
Debug.Print (sqlStatement)
.ActiveConnection = conn
.CommandText = sqlStatement
.CommandType = adCmdText
For Each e In insertElement(1)
Set Pm = .CreateParameter(, adVarChar, 3, 1024, e)
.Parameters.Append Pm
Next e
Set rs = .Execute
End With
其中 insertElement(0)
是字段名称数组,...(1) 是值数组,...(2) 是占位符数组 ?
支持参数化
当我运行这段代码时,我得到一个错误
[Microsoft][ODBC Driver 13 for SQL Server][SQL Server] Incorrect syntax near 'Output'
然而,当我查询sqlStatement
文本时,语句中的任何地方都没有'Output'。文本格式为:
INSERT INTO dbo.mytable ([my_field_1],[my_field_2],[somefieldshaveweirdcharslike+#], ...) VALUES (?, ?, ?, ...)
所以,如果我不直接提供 'Output' 命令,而且我无法直接看到该语句,因为它是在服务器端处理的,我该如何诊断语法?
您应该能够通过迭代您的数组并以您认为合适的方式连接您的值来简单地构建您的 SQL 语句,而不是试图将一堆参数插入一堆问号中。像这样的东西(我假设 insertElement
实际上是一个二维数组而不是一个集合;如果它真的是一个集合那么你需要做一些与 For Each
类似的事情):
sqlStatement = "INSERT INTO dbo.mytable (" & Join(insertElement(0), ", ") & ") VALUES ("
Set cm = New ADODB.Command
With cm
.ActiveConnection = conn
.CommandType = adCmdText
Dim aCount As Integer
aCount = Ubound(insertElement(1))
For i = 0 To aCount - 1
sqlStatement = sqlStatement & "'" & insertElement(1,i) & "'" & _
Iif(i <> aCount - 1, ",", "")
Next
.CommandText = sqlStatement
Set rs = .Execute
End With
综上所述,如果您想更深入地了解错误发生的位置,您可以尝试迭代 Connection
对象的 Errors collection。由于尝试使用连接会产生多个错误,因此仅使用 Err
对象进行故障排除可能有点困难。
最后,最好在服务器端的存储过程中设置您的 INSERT
语句,并以这种方式将值作为参数传递,除非您没有理由担心注入攻击。
我在 SQL 服务器中没有跟踪权限,因此我探索服务器端日志记录的选项有限。
我最终以蛮力方式解决了这个问题,一次添加一个字段,直到我收到错误。
就我而言,根本问题与将 adodb adNumeric
参数类型用于十进制值有关。我将参数类型切换为 adDecimal
,然后在各个参数对象上设置 NumericScale
和 Precision
值。 vba 代码结构如下所示
For Each p In paramArr
If p(1) = adVarChar Then
Set Pm = .CreateParameter(, p(1), 1, Len(p(2)), p(2))
Else
Set Pm = .CreateParameter(, p(1), 1, , p(2))
End If
If p(1) = adDecimal Then
Pm.NumericScale = 3
Pm.Precision = 13
End If
.Parameters.Append Pm
Next p