来自 Excel 的带有 IN 子句的参数化查询
Parameterized query from Excel with IN clause
我有一个从 Excel 2016
sheet 到 IBM DB2
数据库的 MS Query
连接。我对 Excel 单元格使用参数化查询和 link 参数值。虽然 "singular value" 子句(例如 = < > like
有效,但我无法使 IN
子句对 具有多个值 有效,但在其他方面超级简单的查询。
这是我如何生成参数值的简单演示数据集:
D 列公式是 =IF(C2>5,A2&",","")
,它检查 C 列的值是否高于 5,如果 TRUE
,则在 D 列中填充 ID
。我期望使用辅助单元格 merge/concat D 列中的所有值,我想将其用于 IN
子句作为值( 尚未完成 ) .
如何在单元格中使用 "value1, value2, value3, ..."
来 运行 IN
子句查询? 这可能吗? IN
当 linked 单元格保持值 1
时,子句工作正常然而 1, 3
产生错误信息:
"Bad parameter type. Microsoft Excel is expecting a different kind of value than what was provided"
.
为每个单元格使用单独的参数和 OR
子句在技术上看起来可行,但实际上数据集很容易达到 50-100 个值,这意味着大量的参数设置。
查询本身很简单:
select * from PRODUCTS a
where a.prod_ID in (1,3)
或作为 Excel MS 查询备选方案:
select * from PRODUCTS a
where a.prod_ID in ?
这个:
select * from PRODUCTS a
where a.prod_ID in ?
永远行不通。
可行的方法是将字符串传递给可以 return 一组行的函数。
select *
from PRODUCTS a
where a.prod_ID in (select int(column_value)
from table ( split(?,',')) tbl
)
split()
是用户定义的 table 函数,摘自 IBM 的开发人员作品文章:How to split a string into a set of rows (anti-LISTAGG)
CREATE OR REPLACE FUNCTION SPLIT(text VARCHAR(32000), split VARCHAR(10))
RETURNS TABLE(column_values VARCHAR(60))
RETURN WITH rec(rn, column_value, pos) AS
(VALUES (1, VARCHAR(SUBSTR(text, 1,
DECODE(INSTR(text, split, 1),
0,
LENGTH(text),
INSTR(text, split, 1) - 1)),
255),
INSTR(text, split, 1) + LENGTH(split))
UNION ALL
SELECT rn + 1, VARCHAR(SUBSTR(text, pos,
DECODE(INSTR(text, split, pos),
0,
LENGTH(text) - pos + 1,
INSTR(text, split, pos) - pos)),
255),
INSTR(text, split, pos) + LENGTH(split)
FROM rec WHERE rn < 30000 AND pos > LENGTH(split))
SELECT column_value FROM rec;
根据您的平台和 Db2 版本,可能有一些内置选项。
例如,在最近的版本中,您可以传入一个 XML 或 JSON 字符串,并使用 XMLTABLE() 或 JSON_TABLE() 来将字符串拆分成行。
为未来的 google 员工张贴这里。所以这个解决方案对我来说有点开箱即用 - 尽管仍然需要改进。
它检查 M1:M4 范围内的工作表更改事件,然后根据 B1 中准备好的语法填充 IN-clause 查询命令文本。对我来说真的是开箱即用!
不幸的是,它在这里只处理一个 Listobject (1),虽然我有多个应该得到相同处理的对象 - 但无论如何,很棒的东西。
Private Sub Worksheet_Change(ByVal Target As Range)
Dim INvaluesCell As Range
Dim SQLin As String, parts As Variant
Dim i As Long, p1 As Long, p2 As Long
Dim qt As QueryTable
Set INvaluesCell = Range("B1")
If Not Intersect(Target, Range(INvaluesCell, "M1:M4")) Is Nothing Then
SQLin = ""
parts = Split(INvaluesCell.Value, ",")
For i = 0 To UBound(parts)
SQLin = SQLin & "'" & parts(i) & "',"
Next
SQLin = " IN (" & Left(SQLin, Len(SQLin) - 1) & ")"
Set qt = Me.ListObjects(1).QueryTable
p1 = InStr(1, qt.CommandText, " IN (", vbTextCompare)
If p1 > 0 Then
p2 = InStr(p1, qt.CommandText, ")") + 1
qt.CommandText = Left(qt.CommandText, p1 - 1) & SQLin & Mid(qt.CommandText, p2)
End If
End If
End Sub
我有一个从 Excel 2016
sheet 到 IBM DB2
数据库的 MS Query
连接。我对 Excel 单元格使用参数化查询和 link 参数值。虽然 "singular value" 子句(例如 = < > like
有效,但我无法使 IN
子句对 具有多个值 有效,但在其他方面超级简单的查询。
这是我如何生成参数值的简单演示数据集:
D 列公式是 =IF(C2>5,A2&",","")
,它检查 C 列的值是否高于 5,如果 TRUE
,则在 D 列中填充 ID
。我期望使用辅助单元格 merge/concat D 列中的所有值,我想将其用于 IN
子句作为值( 尚未完成 ) .
如何在单元格中使用 "value1, value2, value3, ..."
来 运行 IN
子句查询? 这可能吗? IN
当 linked 单元格保持值 1
时,子句工作正常然而 1, 3
产生错误信息:
"Bad parameter type. Microsoft Excel is expecting a different kind of value than what was provided"
.
为每个单元格使用单独的参数和 OR
子句在技术上看起来可行,但实际上数据集很容易达到 50-100 个值,这意味着大量的参数设置。
查询本身很简单:
select * from PRODUCTS a
where a.prod_ID in (1,3)
或作为 Excel MS 查询备选方案:
select * from PRODUCTS a
where a.prod_ID in ?
这个:
select * from PRODUCTS a
where a.prod_ID in ?
永远行不通。
可行的方法是将字符串传递给可以 return 一组行的函数。
select *
from PRODUCTS a
where a.prod_ID in (select int(column_value)
from table ( split(?,',')) tbl
)
split()
是用户定义的 table 函数,摘自 IBM 的开发人员作品文章:How to split a string into a set of rows (anti-LISTAGG)
CREATE OR REPLACE FUNCTION SPLIT(text VARCHAR(32000), split VARCHAR(10))
RETURNS TABLE(column_values VARCHAR(60))
RETURN WITH rec(rn, column_value, pos) AS
(VALUES (1, VARCHAR(SUBSTR(text, 1,
DECODE(INSTR(text, split, 1),
0,
LENGTH(text),
INSTR(text, split, 1) - 1)),
255),
INSTR(text, split, 1) + LENGTH(split))
UNION ALL
SELECT rn + 1, VARCHAR(SUBSTR(text, pos,
DECODE(INSTR(text, split, pos),
0,
LENGTH(text) - pos + 1,
INSTR(text, split, pos) - pos)),
255),
INSTR(text, split, pos) + LENGTH(split)
FROM rec WHERE rn < 30000 AND pos > LENGTH(split))
SELECT column_value FROM rec;
根据您的平台和 Db2 版本,可能有一些内置选项。
例如,在最近的版本中,您可以传入一个 XML 或 JSON 字符串,并使用 XMLTABLE() 或 JSON_TABLE() 来将字符串拆分成行。
为未来的 google 员工张贴这里。所以这个解决方案对我来说有点开箱即用 - 尽管仍然需要改进。
它检查 M1:M4 范围内的工作表更改事件,然后根据 B1 中准备好的语法填充 IN-clause 查询命令文本。对我来说真的是开箱即用!
不幸的是,它在这里只处理一个 Listobject (1),虽然我有多个应该得到相同处理的对象 - 但无论如何,很棒的东西。
Private Sub Worksheet_Change(ByVal Target As Range)
Dim INvaluesCell As Range
Dim SQLin As String, parts As Variant
Dim i As Long, p1 As Long, p2 As Long
Dim qt As QueryTable
Set INvaluesCell = Range("B1")
If Not Intersect(Target, Range(INvaluesCell, "M1:M4")) Is Nothing Then
SQLin = ""
parts = Split(INvaluesCell.Value, ",")
For i = 0 To UBound(parts)
SQLin = SQLin & "'" & parts(i) & "',"
Next
SQLin = " IN (" & Left(SQLin, Len(SQLin) - 1) & ")"
Set qt = Me.ListObjects(1).QueryTable
p1 = InStr(1, qt.CommandText, " IN (", vbTextCompare)
If p1 > 0 Then
p2 = InStr(p1, qt.CommandText, ")") + 1
qt.CommandText = Left(qt.CommandText, p1 - 1) & SQLin & Mid(qt.CommandText, p2)
End If
End If
End Sub