VBA ADO 将数组参数传递给存储过程

Posted

技术标签:

【中文标题】VBA ADO 将数组参数传递给存储过程【英文标题】:VBA ADO pass array parameter to stored procedure 【发布时间】:2021-12-29 13:01:11 【问题描述】:

我在 VBA MS Excel 文件中有一个 3 列和 100K 行的数组。

我想将此数组传递给 SQL Server 存储过程并在存储过程中将其转换为 Tmp-table 并执行我的“事情..”

如何将数组传递给存储过程?

这是我的 VBA 数组的示例:

Col1 | Col2 | Col3 
1      AAA     XXX
2      BBB     YYY
3      CCC     ZZZ

VBA 代码:

......

Set Cmd = CreateObject("ADODB.Command")

Cmd.CommandType = 4 
Cmd.NamedParameters = True
Cmd.ActiveConnection = DbConn
Cmd.CommandText = "My_SP_WithArrayParam"

''I dont know what parameters to use here:
Cmd.Parameters.Append Cmd.CreateParameter("@Arr", ??? , ?? , ??? , My_100K_Arr)

Cmd.Execute

在 SQL 方面:

Create or alter proc My_SP_WithArrayParam(
                                            @Arr ???
                                            )
as 
begin
    create table #Tbl_From_Excel (
                                ID int
                                ,COL1 nvarchar(60)
                                ,COL2 nvarchar(60)
                                )

    ---Need to insert the array to the tmp table, and I dont know the syntax

end 

【问题讨论】:

SQL Server 没有“数组”对象类型。您要使用的是 Table Type 参数。 @Larnu ,好的,对于表类型我可以传递我的 VBA 数组? 为什么不将 json 格式的文本与数组的内容一起使用并将其作为文本传递。 Sql Server 从版本 13 开始可以处理 json。这是link 可能有用。 @AntonGrig - 将 100K * 3 值转换为 JSON 并将大量字符串发送到 SQL 会很慢,我测试了一种将数组转换为“插入”字符串的类似方法花了 7 分钟变成了一个字符串 发送 100,000 行作为表类型参数也不会有效。我闻到了 XY 问题。 【参考方案1】:

对象数组可以作为结构化参数值传递,例如表值参数、XML 或 json(SQL 2016 及更高版本)。尽管较新的 SQL Server 驱动程序支持表值参数,但 ADODB(又名 ADO 经典)不支持。我建议在 XML 上使用 json 字符串,因为它的有效负载较小,并且可以被 SQL Server 高效解析。

以下是 VBA 示例代码。 SQL 调用只用了几秒钟,但在我的工作站上使用传统的字符串连接构建 json 字符串需要几分钟。在 VBA 中构建高性能字符串需要非常注意细节,但如果你想去那里,似乎有 techniques to improve it considerably。

存储过程:

CREATE OR ALTER PROC My_SP_WithArrayParam
    @Arr nvarchar(MAX)
AS
SET NOCOUNT ON;
    SELECT Col1, Col2, Col3
    INTO #Tbl_From_Excel 
FROM OPENJSON(@arr)
WITH (
     Col1 int
    ,Col2 varchar(100)
    ,Col3 varchar(100)
);
GO

ArrayEntry 类:

Option Explicit

Public Col1 As Long
Public Col2 As String
Public Col3 As String

Public Function getJson()
    Dim json As String
    ` note if double quotes may exist in values, they need to be escaped with a backslash
    ' TODO: string building optimization
    getJson = """Col1"":""" & CStr(Col1) & """,""Col2"":""" & Col2 & """,""Col3"":""" & Col3 & """"
End Function

示例使用代码:

' load 100000 array entries
Dim arrayEntries(100000) As ArrayEntry
Dim i As Long
For i = 0 To 99999
    Set entry = New ArrayEntry
    Set arrayEntries(i) = entry
    entry.Col1 = i
    entry.Col2 = "AAA"
    entry.Col3 = "XXX"
Next i

' build json from array (TODO: string building optimization)
Dim json As String
json = "["
For i = 0 To 99999
    Set entry = arrayEntries(i)
    If i > 0 Then json = json & ","
    json = json & entry.getJson()
Next
json = json & "]"

' call proc with json parameter
con.Open "Provider=MSOLEDBSQL;Data Source=.;Initial Catalog=YourDatabase;Integrated Security=SSPI;"
cmd.ActiveConnection = con
cmd.CommandText = "My_SP_WithArrayParam"
cmd.CommandType = adCmdStoredProc
cmd.Parameters.Append cmd.CreateParameter("@json", adVarChar, adParamInput, -1, json)
cmd.Execute
con.Close
Set cmd = Nothing
Set con = Nothing

【讨论】:

以上是关于VBA ADO 将数组参数传递给存储过程的主要内容,如果未能解决你的问题,请参考以下文章

在 ASP.Net Core 项目中使用 ADO.Net 将 JSON 类型作为参数传递给 SQL Server 2016 存储过程

Excel VBA:将计算结果数组作为参数传递给函数

Excel VBA - 将参数参数传递给 Sub

使用 ADO.NET 传递表值参数

SQL Plus 无法使用 Accept 将参数传递给我的存储过程

将 xml 字符串参数传递给 SQL Server 存储过程