使用 Excel VBA 定义的变量作为 SQL 命令文本的 "IN" 语句
Using an Excel VBA-defined variable as an "IN" statement of SQL command text
我试图将变量传递到 VBA 代码中 SQL 查询的命令文本中,但将 运行 保留为 "Type mismatch" 错误。我在我的电子表格中写了一个简单的等式,它重新创建了 IN 语句的语法,我只想将其放入查询中。
因此,单元格 A1 包含以下内容:
(1, 2, 3)
而我的VBA的相关片段如下:
Dim x as String
x = Sheets("SheetName").Range("A1")
然后在重新创建我的查询的命令文本的一长串代码中(我通过 "record" 功能创建的),我试图按如下方式注入变量:
"Where table.field in " & x & " and table2.field <> 0"
如果重要:
- table 中的字段存储为(int,非空)。
- 我已经使用 MsgBox(x) 来验证它是否适当地存储了字符串
- 字符串不超过 255 个字符的限制
- 我试过使用标准'?'使用 MSQuery 传递参数的功能,同样没有运气
我过去曾使用过这种技巧,但只有一个变量。需要放入 IN 语句的列表将不断变化,所以我只是试图避免必须显式调用每个,或者必须 return 100% 的数据然后过滤它事后出局。
如有任何帮助,我们将不胜感激!对完成同一件事的其他方式持开放态度;只是希望这会起作用,因为它很容易,因为电子表格已经设置好了。
更新:
今天再次研究这个问题,我发现我过度简化了这个例子,我知道没有违反字符串字符限制,所以我假设 IN 子句的长度是可以的。通常情况下,我不应该这样假设。
我发现 IN 子句的长度是一个因素,即使在 255 限制下也是如此。当单元格 A1 的完整长度最多包含 210 个字符时,一切都会正常工作;再举一个例子:
(1, 2, 3, 4, 5, 6, 7, 8, 9 ,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 19000101, 20160101, 20160530, 20160704, 20160905, 20161124, 20161125, 20161223, 20161226, 20170102, 20170103456789123)
如果我将另一个值附加到最后一个数字的末尾,以将字符计数跳到 211,我将遇到 "Type mismatch" 错误。
我试图通过创建另一个变量来容纳字符串的其余部分来避免这种情况,但这也产生了同样的错误。如果我尝试将超过 210 的任何内容填充到代码的单个部分,就会出现错误。
假设单元格 A1 现在包含 210 个长度的版本,下面的代码将执行正常,如果 A1 包含超过 210 个字符,它会给我 "Type mismatch":
Dim x As String
x = Sheets("SheetName").Range("A1")
With ActiveWorkbook.Connections("Query from Database"). _
ODBCConnection
.BackgroundQuery = False
.CommandText = Array( _
"USE Database" & Chr(13) & "" & Chr(10) & "SELECT var.UOM, var.UOMClass" & Chr(13) & "" & Chr(10) & "FROM dbo.Variance var" & Chr(13) & "" & Chr(10) & "WHERE var.UOMC" _
, "lass in" & x & "and var.ModType <>0")
.CommandType = xlCmdSql
.Connection = _
"ODBC;DSN=Database;UID=user01;Trusted_Connection=Yes;APP=Microsoft Office 2010;WSID=COM1077;DATABASE=Database"
.RefreshOnFileOpen = False
.SavePassword = False
.SourceConnectionFile = ""
.SourceDataFile = ""
.ServerCredentialsMethod = xlCredentialsMethodIntegrated
.AlwaysUseConnectionFile = False
End With
With ActiveWorkbook.Connections("Query from Database")
.Name = "Query from Database"
.Description = ""
End With
ActiveWorkbook.Connections("Query from Database").Refresh
目前我只是将 ~230 长度的 IN 语句硬编码到实际的命令文本中,查询运行得很好,但由于这个列表不仅会改变而且还会增长,我仍然很好奇是否存在解决方案。
CommandText 数组的每个元素的最大长度限制为 255 个字符,因此您需要确保不超过该长度。一种方法是将 SQL 构建为单个字符串,然后将其传递给一个函数,该函数将 return 一个部分数组,每个部分都在限制范围内。
参见下面的示例 - SplitMeUp
将 return 一个字符串数组,每个字符串的最大长度为 200 个字符
Sub Tester()
Dim s As String, arr, n, sep
For n = 1 To 200
s = s & sep & n
sep = "-"
Next n
arr = SplitMeUp(s)
Debug.Print Join(arr, vbLf)
End Sub
Function SplitMeUp(strIn As String)
Const MAX_LEN As Long = 200
Dim rv(), n, i
n = Application.Ceiling(Len(strIn) / MAX_LEN, 1)
ReDim rv(0 To n - 1)
For i = 1 To n
rv(i - 1) = Mid(strIn, 1 + ((i - 1) * MAX_LEN), MAX_LEN)
Next i
SplitMeUp = rv
End Function
在您的用例中:
.CommandText = SplitMeUp( _
"USE Database " & vbCrLf & "SELECT var.UOM, var.UOMClass" & _
vbCrLf & " FROM dbo.Variance var WHERE var.UOMClass in" & _
x & " and var.ModType<>0")
我试图将变量传递到 VBA 代码中 SQL 查询的命令文本中,但将 运行 保留为 "Type mismatch" 错误。我在我的电子表格中写了一个简单的等式,它重新创建了 IN 语句的语法,我只想将其放入查询中。
因此,单元格 A1 包含以下内容:
(1, 2, 3)
而我的VBA的相关片段如下:
Dim x as String
x = Sheets("SheetName").Range("A1")
然后在重新创建我的查询的命令文本的一长串代码中(我通过 "record" 功能创建的),我试图按如下方式注入变量:
"Where table.field in " & x & " and table2.field <> 0"
如果重要:
- table 中的字段存储为(int,非空)。
- 我已经使用 MsgBox(x) 来验证它是否适当地存储了字符串
- 字符串不超过 255 个字符的限制
- 我试过使用标准'?'使用 MSQuery 传递参数的功能,同样没有运气
我过去曾使用过这种技巧,但只有一个变量。需要放入 IN 语句的列表将不断变化,所以我只是试图避免必须显式调用每个,或者必须 return 100% 的数据然后过滤它事后出局。
如有任何帮助,我们将不胜感激!对完成同一件事的其他方式持开放态度;只是希望这会起作用,因为它很容易,因为电子表格已经设置好了。
更新:
今天再次研究这个问题,我发现我过度简化了这个例子,我知道没有违反字符串字符限制,所以我假设 IN 子句的长度是可以的。通常情况下,我不应该这样假设。
我发现 IN 子句的长度是一个因素,即使在 255 限制下也是如此。当单元格 A1 的完整长度最多包含 210 个字符时,一切都会正常工作;再举一个例子:
(1, 2, 3, 4, 5, 6, 7, 8, 9 ,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 19000101, 20160101, 20160530, 20160704, 20160905, 20161124, 20161125, 20161223, 20161226, 20170102, 20170103456789123)
如果我将另一个值附加到最后一个数字的末尾,以将字符计数跳到 211,我将遇到 "Type mismatch" 错误。
我试图通过创建另一个变量来容纳字符串的其余部分来避免这种情况,但这也产生了同样的错误。如果我尝试将超过 210 的任何内容填充到代码的单个部分,就会出现错误。
假设单元格 A1 现在包含 210 个长度的版本,下面的代码将执行正常,如果 A1 包含超过 210 个字符,它会给我 "Type mismatch":
Dim x As String
x = Sheets("SheetName").Range("A1")
With ActiveWorkbook.Connections("Query from Database"). _
ODBCConnection
.BackgroundQuery = False
.CommandText = Array( _
"USE Database" & Chr(13) & "" & Chr(10) & "SELECT var.UOM, var.UOMClass" & Chr(13) & "" & Chr(10) & "FROM dbo.Variance var" & Chr(13) & "" & Chr(10) & "WHERE var.UOMC" _
, "lass in" & x & "and var.ModType <>0")
.CommandType = xlCmdSql
.Connection = _
"ODBC;DSN=Database;UID=user01;Trusted_Connection=Yes;APP=Microsoft Office 2010;WSID=COM1077;DATABASE=Database"
.RefreshOnFileOpen = False
.SavePassword = False
.SourceConnectionFile = ""
.SourceDataFile = ""
.ServerCredentialsMethod = xlCredentialsMethodIntegrated
.AlwaysUseConnectionFile = False
End With
With ActiveWorkbook.Connections("Query from Database")
.Name = "Query from Database"
.Description = ""
End With
ActiveWorkbook.Connections("Query from Database").Refresh
目前我只是将 ~230 长度的 IN 语句硬编码到实际的命令文本中,查询运行得很好,但由于这个列表不仅会改变而且还会增长,我仍然很好奇是否存在解决方案。
CommandText 数组的每个元素的最大长度限制为 255 个字符,因此您需要确保不超过该长度。一种方法是将 SQL 构建为单个字符串,然后将其传递给一个函数,该函数将 return 一个部分数组,每个部分都在限制范围内。
参见下面的示例 - SplitMeUp
将 return 一个字符串数组,每个字符串的最大长度为 200 个字符
Sub Tester()
Dim s As String, arr, n, sep
For n = 1 To 200
s = s & sep & n
sep = "-"
Next n
arr = SplitMeUp(s)
Debug.Print Join(arr, vbLf)
End Sub
Function SplitMeUp(strIn As String)
Const MAX_LEN As Long = 200
Dim rv(), n, i
n = Application.Ceiling(Len(strIn) / MAX_LEN, 1)
ReDim rv(0 To n - 1)
For i = 1 To n
rv(i - 1) = Mid(strIn, 1 + ((i - 1) * MAX_LEN), MAX_LEN)
Next i
SplitMeUp = rv
End Function
在您的用例中:
.CommandText = SplitMeUp( _
"USE Database " & vbCrLf & "SELECT var.UOM, var.UOMClass" & _
vbCrLf & " FROM dbo.Variance var WHERE var.UOMClass in" & _
x & " and var.ModType<>0")