我希望能够在 MS Access 2003 中创建参数化查询并将某些表单元素的值提供给该查询,然后获取相应的结果集并使用它们进行一些基本计算。我在弄清楚如何让查询的参数由表单元素填充方面做得很短。如果我必须使用 VBA,那很好。
5 回答
可以直接在 Access 查询中使用对表单上的控件的引用,但将它们定义为参数很重要(否则,最近版本的 Access 中的结果可能无法预测,因为它们曾经是可靠的)。
例如,如果您想通过 MyForm 上的 LastName 控件过滤查询,您可以使用它作为您的条件:
LastName = Forms!MyForm!LastName
然后,您将表单引用定义为参数。生成的 SQL 可能如下所示:
PARAMETERS [[Forms]!MyForm![LastName]] Text ( 255 );
SELECT tblCustomers.*
FROM tblCustomers
WHERE tblCustomers.LastName=[Forms]![MyForm]![LastName];
但是,我会问为什么您需要为此目的保存查询。你对结果做了什么?在表格或报告中显示它们?如果是这样,您可以在表单/报告的 Recordsource 中执行此操作,并使保存的查询不受参数影响,因此可以在其他上下文中使用它而不会弹出提示填写参数。
另一方面,如果您在代码中做某事,只需动态编写 SQL 并使用表单控件的文字值来构造 WHERE 子句。
这是一段代码。它使用参数 txtHospital 更新表:
Set db = CurrentDb
Set qdf = db.QueryDefs("AddHospital")
qdf.Parameters!txtHospital = Trim(Me.HospName)
qdf.ReturnsRecords = False
qdf.Execute dbFailOnError
intResult = qdf.RecordsAffected
下面是一个 SQL 示例:
PARAMETERS txtHospital Text(255);
INSERT INTO tblHospitals (
[Hospital] )
VALUES (
[txtHospital] )
解决此问题的传统方法有以下三种:
- 将参数命名为 cleaver,以便在运行查询时提示用户输入值。
- 表单上的参考字段(可能隐藏)
- 即时构建查询,不要使用参数。
我认为您必须[?enter ISO code of the country]
在表单上注入类似或对字段的引用,例如 : ,这对我来说是错误的[Forms]![MyForm]![LastName]
。
这意味着我们不能在多个地方重复使用相同的查询,不同的字段提供数据,或者必须依靠用户在查询运行时不要弄乱数据输入。我记得,对于用户输入的参数,可能很难多次使用相同的值。
通常,我选择了最后一个选项来动态构建查询,并根据需要更新查询对象。但是,对于 SQL 注入攻击(偶然或故意了解我的用户)来说,这很普遍,而且很恶心。
所以我做了一些挖掘,我在这里找到了以下内容(http://forums.devarticles.com/microsoft-access-development-49/pass-parameters-from-vba-to-query-62367.html):
'Ed. Start - for completion of the example
dim qryStartDate as date
dim qryEndDate as date
qryStartDate = #2001-01-01#
qryEndDate = #2010-01-01#
'Ed. End
'QUOTEING "stallyon": To pass parameters to a query in VBA
' is really quite simple:
'First we'll set some variables:
Dim qdf As Querydef
Dim rst As Recordset
'then we'll open up the query:
Set qdf = CurrentDB.QueryDefs(qryname)
'Now we'll assign values to the query using the parameters option:
qdf.Parameters(0) = qryStartDate
qdf.Parameters(1) = qryEndDate
'Now we'll convert the querydef to a recordset and run it
Set rst = qdf.OpenRecordset
'Run some code on the recordset
'Close all objects
rst.Close
qdf.Close
Set rst = Nothing
Set qdf = Nothing
(我自己没有测试过,只是我在旅行中收集的东西,因为每隔一段时间我都想做这个,但最终使用了我之前提到的一个 kludges)
编辑 我终于有理由使用它了。这是实际的代码。
'...
Dim qdf As DAO.QueryDef
Dim prmOne As DAO.Parameter
Dim prmTwo As DAO.Parameter
Dim rst as recordset
'...
'open up the query:
Set qdf = db.QueryDefs("my_two_param_query") 'params called param_one and
'param_two
'link your DAP.Parameters to the query
Set prmOne = qdf.Parameters!param_one
Set prmTwo = qdf.Parameters!param_two
'set the values of the parameters
prmOne = 1
prmTwo = 2
Set rst = qdf.OpenRecordset(dbOpenDynaset, _
dbSeeChanges)
'... treat the recordset as normal
'make sure you clean up after your self
Set rst = Nothing
Set prmOne = Nothing
Set prmTwo = Nothing
Set qdf = Nothing
让我们举个例子。参数化查询如下所示:
Select Tbl_Country.* From Tbl_Country WHERE id_Country = _
[?enter ISO code of the country]
并且您希望能够从表单中获取此值([?enter ... country] 之一),其中您有控件和一些数据。嗯......这可能是可能的,但它需要一些代码规范化。
一种解决方案是让您的表单控件以某种逻辑命名,例如fid_Country
用于保存id_Country
值的控件。然后,您可以将查询作为字符串:
qr = "Select Tbl_Country.* From Tbl_Country WHERE id_Country = [fid_country]"
在表单中输入所有请求的数据后,按“查询”按钮。逻辑将浏览所有控件并检查它们是否在查询中,最终将参数替换为控件的值:
Dim ctl as Control
For each ctl in Me.controls
If instr(qr,"[" & ctl.name & "]") > 0 Then
qr = replace(qr,"[" & ctl.name & "]",ctl.value)
End if
Next i
这样做,您将获得一个完全更新的查询,其中参数已被真实数据替换。根据 fid_country 的类型(字符串、GUID、日期等),您可能需要添加或不添加一些额外的双引号,以获得最终查询,例如:
qr = "Select Tbl_Country.* From Tbl_Country WHERE id_Country = ""GB"""
这是一个完全兼容 Access 的查询,可用于打开记录集:
Set rsQuery = currentDb.openRecordset(qr)
我想你已经完成了。
当您的目标是开发 Access 应用程序时,此主题至关重要。您必须为用户提供一种从其 GUI 查询数据的标准方法,不仅可以启动查询,还可以过滤连续表单(就像 Excel 使用“自动过滤”选项一样)和管理报告参数。祝你好运!
简单的方法在这里Microsoft 'setparameter' 信息页面
DoCmd.SetParameter "frontMthOffset", -3
DoCmd.SetParameter "endMthOffset", -2
DoCmd.OpenQuery "QryShowDifference_ValuesChangedBetweenSELECTEDMonths"
其中 Access 查询的 SQL 实际上在 SQL 中包含 [frontMthOffset]。例如
"select blah from mytable where dateoffset=[frontMthOffset]"
这一切都行得通!