运行 SQL 在 Excel 中查询

Run SQL IN queries in Excel

Objective

我想 运行 SQL 使用 IN 语句查询到 Excel 文件并使用动态参数。

查询

首先可以是:

SELECT feature1 
FROM table 
WHERE feature2 IN (?) 

or

SELECT feature1 
FROM table 
WHERE feature2 IN ? 

无论参数如何,第二个都有系统误差

Syntax error or access violation

所以我专注于第一个。

参数

我在指定参数列表时遇到问题(数据 -> 请求和连接 -> 连接 -> 定义 -> 参数):

最后但同样重要的是,当它是硬编码时,这个returns Something:

SELECT feature1 
FROM table 
WHERE feature2 IN ('a', 'b', 'c') 

问题

发生了什么事?如何动态指定多个参数?有没有办法可视化这个构建的查询来检查出了什么问题?或者有什么技巧可以避免这个问题?

最好不要VBA

使用 Excel 2019 和 Microsoft SQL Server 2012(否 STRING_SPLITOPENJSON

编辑

根据答案和这个 ,我尝试使用这个 sql 查询来避免使用 STRING_SPLITOPENJSON:

SELECT feature1 
FROM table 
WHERE feature2 IN (
    SELECT Split.a.value('.', 'NVARCHAR(MAX)') DATA
    FROM (
         SELECT CAST('<X>'+REPLACE( ? , ',', '</X><X>')+'</X>' AS XML) AS String
         ) AS A
    CROSS APPLY String.nodes('/X') AS Split(a)
);

但是,它不理解通过 Excel 的参数,而当它在查询中被硬编码 时它可以工作。

您必须指定参数列表并相应地分配值。例如,对于 a,b,c,您必须创建 3 个查询参数

SELECT feature1 FROM table WHERE feature2 IN (?,?,?)

参数是单个值。

您不能直接创建 IN 查询。但是,您可以将参数作为逗号分隔值或 xml 或 json 字符串发送,以便在服务器端解析为 table。这是一个简单的例子,使用 Northwind 示例数据库 + json,查询是:

SELECT * FROM [Northwind]..[Products]
WHERE ProductID IN
(
    SELECT value FROM OPENJSON(@Json)
)
ENDTEXT

'  A Json array of integers as parameter
Json = "[1, 3, 5, 6]" 

编辑:样本 XML:

Sub test()
Dim query As String
Dim myParameters As String

query = "DECLARE @hDoc int" & vbCrLf & _
"exec sp_xml_preparedocument @hDoc OUTPUT, ?" & vbCrLf & _
"SELECT * FROM [Northwind]..[Products]" & vbCrLf & _
"WHERE ProductID IN" & vbCrLf & _
"(SELECT id FROM OPENXML(@hDoc, '/root/row', 1) WITH (id int))" & vbCrLf & _
"EXEC sp_xml_removedocument @hDoc"

myParameters = "<root>" & vbCrLf & _
        "<row id=""1""/>" & vbCrLf & _
        "<row id=""3""/>" & vbCrLf & _
        "<row id=""5""/>" & vbCrLf & _
        "<row id=""8""/>" & vbCrLf & _
        "<row id=""9""/>" & vbCrLf & _
    "</root>"
    

    Dim connectionstring As String
    Dim cn As ADODB.Connection
    Dim cmd As ADODB.Command
    Dim p As ADODB.Parameter
    Dim rs As ADODB.Recordset



    connectionstring = "Provider=SQLNCLI11.0;Data Source=.\SQLExpress;" & _
                  "Initial Catalog=Northwind;" & _
                  "Integrated Security=SSPI;"

    Set cn = New ADODB.Connection
    Set rs = New ADODB.Recordset
    Set cmd = New ADODB.Command
    cn.Open connectionstring

cmd.ActiveConnection = cn
cmd.CommandText = query
Set p = cmd.CreateParameter("myValues", adVarChar, adParamInput, -1)
p.Value = myParameters
cmd.Parameters.Append p

' Execute command
Set rs = cmd.Execute
Sheets(1).Range("A1").CopyFromRecordset rs
End Sub

PS:我不是 VB 也不是 VB 人,我真的会用另一种语言来做这件事,但无论如何这也行。

EDIT2:顺便说一句:

exec sp_executesql N'DECLARE @hDoc int
exec sp_xml_preparedocument @hDoc OUTPUT, @P1
SELECT * FROM [Northwind]..[Products]
WHERE ProductID IN
(SELECT id FROM OPENXML(@hDoc, ''/root/row'', 1) WITH (id int))
EXEC sp_xml_removedocument @hDoc',N'@P1 varchar(max)','<root>
<row id="1"/>
<row id="3"/>
<row id="5"/>
<row id="8"/>
<row id="9"/>
</root>'

至SQL 服务器。您也可以自己使用 sp_executesql 并创建一个更简单的 IN 查询,但是如果您不能很好地控制生成的代码,这可能很危险。

好的,根据答案和这个 post,此方法可以在 sql 查询中使用 excel 设置多个参数(和未知大小)。 没有使用IN语句但是结果是一样的

SQL :

SELECT feature1 
FROM database
WHERE ?
LIKE '%,' + feature2 + ',%' ;

这里是?必须看起来像 ',a,b,c,'

Excel:

="'," & TEXJOIN(",",TRUE,A:A) & ",'"

这没有针对大量行进行优化,因此也欢迎优化解决方案