【问题标题】:Parameterized query from Excel with IN clause带有 IN 子句的 Excel 参数化查询
【发布时间】:2023-03-19 05:35:01
【问题描述】:

我有一个从Excel 2016 表到IBM DB2 数据库的MS Query 连接。我使用参数化查询并将参数值链接到 Excel 单元格。虽然= < > like 等“单值”子句可以工作,但我无法让IN 子句处理多个值,否则就是超级简单的查询。

这是我如何生成参数值的简单演示数据集:

D 列公式是 =IF(C2>5,A2&",",""),它检查 C 列值是否大于 5,如果 TRUE 则在 D 列中填充 ID。我希望使用辅助单元格来合并/合并列 D 中的所有值,我想将其用于 IN 子句作为值(尚未完成)。

如何在单元格中使用"value1, value2, value3, ..." 来运行IN 子句查询? 有可能吗?IN 子句在链接单元格保持值 11, 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 Query 替代方案:

select * from PRODUCTS a
where a.prod_ID in ?

【问题讨论】:

  • 一般来说,参数不能与IN 很好地混合使用,如果您正在动态构建 SQL,那么您可以像您提到的那样为每个值添加一个参数:在一个可管理的循环中。
  • 嗨蒂姆!我正在关注您,但不幸的是,还没有深入到无法实施的程度。您能否详细说明或参考一些材料,尤其是 Excel 环境使用?
  • 什么平台和版本的 Db2
  • 有点像 Christian 的回答:stackoverflow.com/questions/9384446/… 但在 VBA 中

标签: sql excel db2 parameterized-query


【解决方案1】:

这个:

select * from PRODUCTS a
where a.prod_ID in ?

永远不会工作。

可行的方法是将字符串传递给可以返回一组行的函数。

select * 
from PRODUCTS a
where a.prod_ID in (select int(column_value)
                    from table ( split(?,',')) tbl
                   )

split() 是一个用户定义的表函数,取自 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() 将字符串拆分为行。

【讨论】:

    【解决方案2】:

    在此处发布此内容以供未来的 Google 员工使用。所以这个解决方案对我来说有点开箱即用 - 尽管仍然需要改进。

    它检查 M1:M4 范围内的工作表更改事件,然后根据 B1 中准备好的语法填充 IN 子句查询命令文本。对我来说真的是开箱即​​用!

    不幸的是,它在这里只处理一个 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
    

    【讨论】:

      猜你喜欢
      • 2010-10-13
      • 2010-12-17
      • 1970-01-01
      • 2016-04-02
      • 1970-01-01
      • 1970-01-01
      • 2014-05-02
      • 1970-01-01
      • 2018-07-07
      相关资源
      最近更新 更多