如何将参数传递给SQL(Excel)中的查询
Posted
技术标签:
【中文标题】如何将参数传递给SQL(Excel)中的查询【英文标题】:how to pass parameters to query in SQL (Excel) 【发布时间】:2011-07-23 00:42:05 【问题描述】:我将 Excel“链接”到 Sql,它运行良好 - 我编写了一些 SQL 脚本,运行良好。我要做的就是将参数传递给查询。就像每次刷新一样,我希望能够将参数(过滤条件)传递给 Sql Query。 在“连接属性”参数按钮被禁用。所以我不能进行参数查询。 谁能帮帮我?
【问题讨论】:
你需要更精确,例如我们在谈论什么样的SQL? (MS SQL Server、Oracle 等)。但是,您可以在任何情况下阅读存储过程,这是您在 SQL 中传递参数的方式,除非您准备一个字符串,您可以动态更新,然后执行它。 【参考方案1】:这篇文章已经足够老了,这个答案对 OP 来说可能没什么用,但我花了很长时间试图回答同样的问题,所以我想我会用我的发现来更新它。
此答案假定您的 Excel 文档中已经有一个有效的 SQL 查询。有很多教程向您展示如何在 Web 上完成此操作,并且有很多教程解释了如何向其中添加参数化查询,但似乎没有一个适用于 现有的 OLE DB 查询。
因此,如果您像我一样收到了一个带有有效查询的旧版 Excel 文档,但用户希望能够根据其中一个数据库字段过滤结果,而如果您像我一样都不是Excel 或 SQL 大师,或许能帮到你。
对此问题的大多数网络回复似乎都说您应该添加“?”在您的查询中让 Excel 提示您输入自定义参数,或者将提示或单元格引用放在参数应该位于的 [括号] 中。这可能适用于 ODBC 查询,但它似乎不适用于 OLE DB,在前一种情况下返回“没有为一个或多个必需参数提供值”和“无效的列名 'xxxx'”或“未知对象” 'xxxx'”在后两个中。同样,使用神话般的“参数...”或“编辑查询...”按钮也不是一个选项,因为在这种情况下它们似乎永久变灰。 (作为参考,我使用的是 Excel 2010,但使用的是 Excel 97-2003 工作簿 (*.xls))
然而,我们可以做的是添加一个参数单元格和一个带有简单例程的按钮,以便以编程方式更新我们的查询文本。
首先,在外部数据表(或任何地方)上方添加一行,您可以在其中将参数提示放在空单元格和按钮旁边(开发人员->插入->按钮(表单控件)-您可能需要启用开发人员选项卡,但您可以在其他地方了解如何执行此操作),如下所示:
接下来,在外部数据(蓝色)区域中选择一个单元格,然后打开数据->全部刷新(下拉菜单)->连接属性...查看您的查询。下一节中的代码假定您的查询中已经有一个参数(连接属性->定义->命令文本),格式为“WHERE (DB_TABLE_NAME.Field_Name = ‘Default Query Parameter’)”(包括括号)。显然,“DB_TABLE_NAME.Field_Name”和“默认查询参数”在您的代码中需要有所不同,这取决于数据库表名称、数据库值字段(列)名称以及打开文档时要搜索的一些默认值(如果你有自动刷新设置)。记下“DB_TABLE_NAME.Field_Name”值,因为您将在下一部分中需要它,以及查询的“连接名称”,可以在对话框顶部找到。
关闭连接属性,然后按 Alt+F11 打开 VBA 编辑器。如果您还没有,请在“项目”窗口中右键单击包含您的按钮的工作表名称,然后选择“查看代码”。将以下代码粘贴到代码窗口中(建议复制,因为单引号/双引号很冒险且必要)。
Sub RefreshQuery()
Dim queryPreText As String
Dim queryPostText As String
Dim valueToFilter As String
Dim paramPosition As Integer
valueToFilter = "DB_TABLE_NAME.Field_Name ="
With ActiveWorkbook.Connections("Connection name").OLEDBConnection
queryPreText = .CommandText
paramPosition = InStr(queryPreText, valueToFilter) + Len(valueToFilter) - 1
queryPreText = Left(queryPreText, paramPosition)
queryPostText = .CommandText
queryPostText = Right(queryPostText, Len(queryPostText) - paramPosition)
queryPostText = Right(queryPostText, Len(queryPostText) - InStr(queryPostText, ")") + 1)
.CommandText = queryPreText & " '" & Range("Cell reference").Value & "'" & queryPostText
End With
ActiveWorkbook.Connections("Connection name").Refresh
End Sub
将“DB_TABLE_NAME.Field_Name”和“连接名称”(在两个位置)替换为您的值(需要包含双引号以及空格和等号)。
将“单元格引用”替换为您的参数所在的单元格(从头开始的空单元格) - 我的是第一行中的第二个单元格,所以我输入了“B1”(再次,双引号是必要的) .
保存并关闭 VBA 编辑器。
在适当的单元格中输入您的参数。
右键单击您的按钮以将 RefreshQuery 子分配为宏,然后单击您的按钮。查询应该更新并显示正确的数据!
注意事项: 仅当您的查询中有连接或其他出现等号时,才需要使用整个过滤器参数名称(“DB_TABLE_NAME.Field_Name =”),否则只需一个等号就足够了,Len() 计算将是多余的。 如果您的参数包含在也用于连接表的字段中,则需要将代码中的“paramPosition = InStr(queryPreText, valueToFilter) + Len(valueToFilter) - 1”行更改为“paramPosition = InStr( Right(.CommandText, Len(.CommandText) - InStrRev(.CommandText, "WHERE")), valueToFilter) + Len(valueToFilter) - 1 + InStr(.CommandText, "WHERE")" 以便它只查找 valueToFilter 在“WHERE”之后。
这个答案是在 datapig 的“BaconBits”的帮助下创建的,我在其中找到了查询更新的基本代码。
【讨论】:
另外请注意,如果您的参数中包含括号,则更新代码将无法正常工作。 (它依靠括号来确定它在查询字符串中的位置)。您可以重新编码 queryPostText 字符串以根据 second (等)关闭括号找到它的长度以使其工作。 这太棒了 :) 谢谢,帮了我很多。 嗨,我正在通过 OLE DB 连接阅读,我的查询总共有 3 个表和 2 个连接,我认为这对我不起作用吗? @Mowgli 是的,它可以工作,但正如我在最后一段中指出的那样,如果您尝试基于用于连接的相同字段进行过滤(参数化),您将拥有更改 paramPosition 设置。 从有效的外部数据源形成表格后,参数按钮“ungreys”本身...因此,如果您填充了表格(没有参数),然后返回连接属性,您应该会看到可供您设置的参数按钮。 (别忘了在你的 SQL 查询中使用fieldname=?
)【参考方案2】:
这取决于您尝试连接的数据库、创建连接的方法以及您使用的 Excel 版本。 (也很可能是您计算机上相关 ODBC 驱动程序的版本。)
以下示例在我的本地计算机上使用 SQL Server 2008 和 Excel 2007。
当我使用数据连接向导(在功能区的“数据”选项卡上的“获取外部数据”部分的“来自其他来源”下)时,我看到了与您所做的相同的事情:“参数”按钮被禁用,并添加了一个查询的参数,例如 select field from table where field2 = ?
,导致 Excel 抱怨未指定参数的值,并且未保存更改。
当我使用 Microsoft Query(与数据连接向导相同的位置)时,我能够创建参数,为它们指定显示名称,并在每次运行查询时输入值。调出该连接的连接属性,启用“参数...”按钮,并且可以根据需要修改和使用参数。
我也可以使用 Access 数据库来做到这一点。 Microsoft Query 可用于创建针对其他类型数据库的参数化查询似乎是合理的,但我现在无法轻松测试。
【讨论】:
以上是关于如何将参数传递给SQL(Excel)中的查询的主要内容,如果未能解决你的问题,请参考以下文章