如何在Excel中使用此查询?查询错误还是Excel不够强大?

时间:2013-03-06 14:18:01

标签: sql excel parameters odbc ms-query

SELECT Orders.PO_No, Orders.Order_No
FROM DBase.dbo.Orders Orders
Where Orders.PO_No = (Select Top 1 Orders.PO_No From Orders Where Order_No = ?)

如果我特意使用

SELECT Orders.PO_No, Orders.Order_No
FROM DBase.dbo.Orders Orders
Where Orders.PO_No = (Select Top 1 Orders.PO_No From Orders Where Order_No = '555555')

它返回值如何使用用户输入的值在Sheet1上的Cell $ A $ 1中编写此查询我试过了吗?在SQL语句框下的命令文本定义和内部MSQuery中。

使用命令文本字段时?我得到一个新的参数调用Parameter1,但当我将Parameter1的值设置为=单元格时,我得到以下错误:

[Microsoft] [ODBC SQL Server驱动程序]语法错误或访问冲突

并且

[Microsoft] [ODBC SQL Server驱动程序]无效的描述符索引

即使我确保单元格值为555555

3 个答案:

答案 0 :(得分:0)

对不起,我没有SQLServer方便测试这个,但我的猜测是,正如Jeff评论的那样,当一个String被预期时,你传递的是Long。试试这个

Where Orders.PO_No = (Select Top 1 Orders.PO_No From Orders Where Order_No = "'" & ? & "'")

我不确定 语法是否正确,但基本上你需要在问号周围加上引号。格式化单元格不起作用,因为Excel只是将值放入问号所在的SQL语句中。它不会评估单元格的值,并包含日期或类似内容的字符串或哈希值的引号。即使单元格值是字母(而不是看起来像数字的字符串),由于缺少单引号,SQL也无法工作。

我想。

答案 1 :(得分:0)

我提出了以下VBA,它运行速度超快,易于更改。

Private Sub Worksheet_Change(ByVal Target As Range)
    If Target.Address = "$A$1" Then
        With Range("Table_Query_from_DBase_1[[#Headers],[PO_No]]").ListObject.QueryTable
        .CommandText = Array( _
        "SELECT Orders.PO_No, Orders.Order_No" & Chr(13) & "" & Chr(10) & "FROM DBase.dbo.Orders Orders" & Chr(13) & "" & Chr(10) & "Where Orders.PO_No =(Select Top 1 Orders.PO_No From Orders Where Order_No = '" & Range("A1").Value & "')" _
                   )
        End With
    End If
End Sub

无论何时在Cell A1中输入新值,代码都会自动更改CommandText(Select Statement)。

同样通过使用With命令,您可以包含更多内容,例如在更改参数后通过添加

使其自动刷新
.Refresh BackgroundQuery:=False 
结束前的

您可以通过将CommandText放入分配给按钮的宏或工作表刷新或几乎无穷无尽的变量来更改CommandText的更改时间

答案 2 :(得分:0)

与user2140261的解决方案类似,使用worksheet_change事件触发更改:

Private Sub Worksheet_Change(ByVal Target As Range)
    If Target.Address = "$A$1" Then
        With ActiveSheet.Range("Table_Name").ListObject.QueryTable
            .CommandText = ChangeParameter(.CommandText, "ParameterFlag", Range(Target.Address))
        End With
        ActiveWorkbook.RefreshAll
    End If
End Sub

在上面,$ A $ 1是动态信息的位置(例如,日期),SQL表是Table_Name,ParameterFlag是要替换的SQL代码中的参数(见下文)。 这是用于更改SQL代码的ChangeParameter函数:

Function ChangeParameter(src As String, parameter As String, newValue As String)
    'Replace src text surrounded by startParameter and endParameter with newValue

    Dim startPosn As Long, endPosn As Long
    Dim startParameter As String, endParameter As String

    startParameter = "/*<" & parameter & ">*/"
    endParameter = "/*</" & parameter & ">*/"
    startPosn = 0
    Do
        startPosn = InStr(startPosn + 1, src, startParameter)
        If startPosn Then
            endPosn = InStr(startPosn + Len(startParameter), src, endParameter)
            If endPosn Then
                src = Left(src, startPosn + Len(startParameter) - 1) & newValue & Mid(src, endPosn)
            Else
                Exit Do
            End If
        End If
    Loop While startPosn
    ChangeParameter = src
End Function

如果所需的SQL代码是,例如:

SELECT * FROM mytable WHERE startDate > '7/1/2015'

然后在命令文本框中编辑它,说:

SELECT * FROM mytable WHERE /*<StartDate>*/'7/1/2015'/*</StartDate>*/

呼叫线路将是:

.CommandText = ChangeParameter(.CommandText, "StartDate", "'" & Range(Target.Address) & "'")

(日期作为常量存储在代码中,因此需要用单引号括起电子表格的值)。所有这一切都有效,因为/* */包围的注释被忽略,即使它们位于一行中间,通常是一个糟糕的编码实践,但在这里很有用。

原始SQL代码中由参数标志(在本例中为/*<StartDate>*//*</StartDate>*/)包围的所有位置都将替换为新值(“'”&amp; Range(Target.Address) &amp;“'”在这种情况下)。下次更改目标单元$ A $ 1时,将再次运行该调用并再次更改参数,而无需知道其先前的值是什么。

可以对要更改的每个参数以及包含要更改的参数的每个基于SQL的表使用对ChangeParameter的多次调用。

当然,如果参数替换适用于复杂的代码,那么这一切都不是必需的......