【问题标题】:How do I get the data from an SQL query in microsoft Access VBA?如何从 Microsoft Access VBA 中的 SQL 查询中获取数据?
【发布时间】:2010-11-10 01:06:44
【问题描述】:

嘿,我刚刚学会了如何将我的 SQL 语句放入 VBA(或至少将它们写出来),但我不知道如何返回数据?

我有几个基于查询的表格(图表表格),我针对这些查询运行非常常规的参数,只是改变了时间范围(比如当月的前 10 名销售额)。然后我有程序可以自动将图表对象传输到 powerpoint 演示文稿中。所以我预先构建了所有这些查询(如 63)和要匹配的图表形式(嗯,是的....63...我知道这很糟糕),然后所有这些东西都设置在“open/关闭”事件触发下一个(这就像我成为黑客的最佳尝试......或多米诺骨牌;无论你喜欢哪个)。

所以我试图学习如何在 VBA 中使用 SQL 语句,以便最终我可以在那里完成所有这些(我可能仍然需要保留所有这些图表形式,但我不知道,因为我显然缺乏理解) .

所以除了我在顶部提出的问题之外,任何人都可以提供建议吗? 谢谢

【问题讨论】:

  • 对不起,我总是忘记....我使用的是 Microsoft Access 2000
  • @Justin,如果他们有帮助,最好给下面帮助过你的好人投票:)

标签: sql ms-access vba


【解决方案1】:

它有点过时了,所以您可能想要获取book on the subject。但是,这里有很多 access resources 和一些 tutorials and examples。但是,基本上...

Dim dbs As Database
Dim rs As Recordset
Dim strSQL As String
Set dbs = CurrentDb

strSQL = 'your query here

Set rs = dbs.OpenRecordset(strSQL)

If Not (rs.EOF And rs.BOF) Then
  rs.MoveFirst
  'get results using rs.Fields()
Else

'Use results

每条评论:看看recordset class。它包含一个名为 Fields 的集合,它们是从查询返回的列。在不知道您的架构的情况下,很难说,但是...

rs.MoveFirst
Do While Not rs.EOF
   'do something like rs("SomeFieldName") 
   rs.MoveNext
Loop

就像我说的,最好的办法是买一本关于这个主题的书,他们有很多例子。

【讨论】:

  • 并非所有游标类型都会返回 RecordCount。这样做更安全。EOF ...
  • 代码示例是DAO,如果有记录,所有记录集类型返回的记录计数至少为1,因此无需检查EOF和BOF,检查RecordCount0就足够了。如果您要将代码移植到其他数据接口,那么您的观点是相关的,但在本代码示例中它肯定是完全不符合的,这很明显是 DAO。
  • 我会 JP,但我了解表面(就像所有事情一样)。再次感谢伙计!
  • 如果你有一个准确的记录数,那么使用它会比每次迭代都测试 EOF 更有效。您必须测试多少毫秒的效率;)
  • 感谢@David-W-Fenton 提供 DAO 的信息,所以我将看看 p.campbell 的解决方案,即 ADODB(我使用它)。
【解决方案2】:

使用参数化的 querydef 并从 vba 调用它。
该查询更易于设计...易于测试...并且可以通过 VBA 或表单轻松访问。

dim qd as querydef
set qd = currentdb.querydefs!myquerydef

qd.parameters!parm1=val1

....

要么 qd.执行

dim rs as recordset
set rs = qd.openrecordset()

YMMV ...

【讨论】:

  • 顺便说一句...这使用了 DAO 库。确保在“参考”中选择的 DAO 高于 ADO。
  • 一个限制是您不能在 TOP N SQL 语句中参数化 N。
【解决方案3】:

这是一个您可能会考虑重构以接收字符串的函数,您将能够在代码中的任何地方重用。

所以有一个 CONST 或为您的 SQL 语句构建一个字符串,并弹出您的 SANITIZED、NON SQL INJECTED 字符串作为参数:)

strSQL = "SELECT * FROM Customer WHERE ID = " & EnsureParamIsNotSQLInjection(customerID)

...然后从您需要获取记录集/数据/执行语句的任何地方调用函数/子。考虑创建一些数据访问函数/子程序,您可以在其中简单地运行 UPDATE 语句、检索单个值或检索完整的记录集。

这里的关键是将这些功能全部集中在一个地方,并在所有地方重复使用它们。这是 VBScript 中的示例。

Sub DoStuff(strSQL)

   Set adoCon = Server.CreateObject("ADODB.Connection")


    strConnString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath("db\Database.mdb") 
    'strConnString = "DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=" & Server.MapPath("db\Database.mdb")

   adoCon.Open strConnString

   Set rsMain = Server.CreateObject("ADODB.Recordset")

   rsMain.Open strSQL, adoCon

   Do While NOT rsMain.EOF
      customerName = rsMain("CustomerName") 'silly example
      RsMain.MoveNext
   Loop

   rsMain.Close

   Set adoCon = Nothing
End Sub

【讨论】:

  • 是的,听起来很酷。不错的主意。我知道如何将公共函数调用到表单的子(事件)中,但是函数呢……它们的工作方式相同吗?
  • @pcampbell:您使用 odbc 连接的任何原因?如果您使用 OLE DB 连接,您将不会从许多 ADO 中受益,例如"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath("db\Database.mdb")
  • ...我不确定您使用的是什么“服务器”对象来提供 ADO 对象(更常见的是使用本地计算机的注册表)并解析数据库文件的路径.考虑到这里的大多数人不会引用服务器对象,并且只会在这些行上得到“需要对象”错误。
  • @oneday:感谢 cmets。这只是一个sn-p,真的。人们应该根据自己的情况随意修改他们在 StackOverflow 上找到的代码。
  • 我使用 Access 2016 并具有以下适用于 .accdb 的提供程序和数据源字符串:strVerb = "Provider=Microsoft.ACE.OLEDB.12.0;" & _ "Data Source=C:/test.accdb"
【解决方案4】:

虽然复杂,但您的方法比尝试在 VBA 中构建 SQL 语句更容易。请记住,单独保存查询可以让您直观地操作它们。此外,还有一些性能优势。

更好地理解 SQL 将帮助您整合和简化现有查询(如果它们甚至需要简化的话。听起来他们做了很多工作,所以无论如何您可能需要所有 64 个查询)。

也就是说,在代码中执行 SQL 查询非常容易:

Dim strSQL as String
strSQL = "UPDATE Table MyTable SET fieldname = 1 WHERE fieldname = 0;"
DoCmd.RunSQL strSQL

【讨论】:

  • 谢谢。我唯一感到紧张/困惑的是这个东西中的所有这些对象,当我需要将它转储到前端/mde时。这将是我第一次这样做,因为我有限的访问经验一直只是保持在后端状态
  • 使用工具/数据库实用程序中的数据库拆分器很容易将表与其他所有内容分开。
【解决方案5】:

似乎没有人提到的另一种方法是将您的图形绑定到单个保存的 QueryDef,然后在运行时重写 QueryDef。现在,我不建议为大多数上下文更改保存的 QueryDef,因为它会导致前端膨胀并且通常甚至没有必要(使用保存的 QueryDef 的大多数上下文可以在它们所在的上下文中以一种或其他方式过滤)例如,作为表单的 Recordsource,您只需在 DoCmd.OpenForm 中传递一个参数)。

图表不同,因为驱动图表的 SQL 不能在运行时更改。

有些有建议的参数,但打开一个带有图形的表单,该表单使用带有参数的 SQL 字符串将弹出默认参数对话框。避免这种情况的一种方法是使用对话框表单来收集条件,然后将对对话框表单上的控件的引用设置为参数,例如:

PARAMETERS [Forms]![MyForm]![ID] Long;

如果您使用表单引用,那么执行此操作至关重要,因为从 Access 2002 开始,当控件为 Null 时,Jet Expression Service 并不总是正确处理这些。将它们定义为参数可以纠正该问题(在 Access XP 之前不存在)。

必须为图形重写 QueryDef 的一种情况是,如果您希望允许用户在 TOP N SQL 语句中选择 N。换句话说,如果您希望他们能够选择 TOP 5 或 TOP 10 或 TOP 20,则必须更改保存的 QueryDef,因为 N 无法参数化。

【讨论】:

    【解决方案6】:

    “如果你想允许用户在 TOP N SQL 语句中选择 N”——好吧,你可以使用相关子查询(而不是动态 SQL),例如(ANSI-92 查询模式语法):

    CREATE PROCEDURE GetOrdersTopN
    (
     :N INTEGER
    )
    AS 
    SELECT O1.OrderDate, O1.CustomerID
      FROM Orders AS O1
     WHERE :N >= (SELECT COUNT(*) + 1
                   FROM Orders AS O2
                  WHERE O1.OrderDate < O2.OrderDate);
    

    ...但上次我检查 Access 引擎并没有针对这种结构进行很好的优化(委婉地说)。

    【讨论】:

    • 谢谢!不确定我是否还在那里,但这就是我的学习方式!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    相关资源
    最近更新 更多