【问题标题】:Control Database form Excel through VBA通过 VBA 控制数据库表单 Excel
【发布时间】:2017-07-30 10:40:28
【问题描述】:

我正在尝试创建一个 excel 插件,它具有一组函数以从数据库中提取值(我使用 MS SQL Server)。所以我的查询将只返回一个记录集。我在我的 vba 代码中使用了类似下面的内容。

Using Excel VBA to run SQL query

但问题是,如果我在 100 个单元格中有自定义函数,宏每次都会连接到数据库并从数据库中检索数据。

有没有一种方法可以让我建立一个连接并使用该连接编写任意数量的查询?

【问题讨论】:

    标签: sql-server excel vba


    【解决方案1】:

    很简单,运行所有 100 个函数/循环来访问数据库。一个你已经完成然后关闭连接。看看下面你修改过的代码...

    Option Explicit
    
    Sub ConnectSqlServer()
    
        Dim conn As ADODB.Connection
        Dim rs As ADODB.Recordset
        Dim sConnString As String
    
        ' Create the connection string.
        sConnString = "Provider=SQLOLEDB;Data Source=INSTANCE\SQLEXPRESS;" & _
                      "Initial Catalog=MyDatabaseName;" & _
                      "Integrated Security=SSPI;"
    
        ' Create the Connection and Recordset objects.
        Set conn = New ADODB.Connection
        Set rs = New ADODB.Recordset
    
        ' Open the connection and execute.
        conn.Open sConnString
    
        '>>>> run 100 loops
        Dim i As Integer
    
        For i = 1 To 100
            Set rs = conn.Execute("SELECT * FROM Table" + 1 + ";")
    
            ' Check we have data.
            If Not rs.EOF Then
                ' Transfer result.
                ' I assume that you've 100 Sheets
                Sheets(i).Range("A1").CopyFromRecordset rs
            ' Close the recordset
                rs.Close
            Else
                MsgBox "Error: No records returned.", vbCritical
            End If
        Next
    
        ' Clean up
        If CBool(conn.State And adStateOpen) Then conn.Close
        Set conn = Nothing
        Set rs = Nothing
    
    End Sub
    

    我添加了 100 个循环并在关闭与数据库的连接之前运行它。 希望有用。

    【讨论】:

    • 我认为你没有抓住重点。如果我正确理解了 OP,那么他/她想用 sub 一次提取一个值。也许这甚至会成为 UDF 的一部分。因此,除非有办法预先聚合所有查询(这样子知道它必须运行的所有查询),否则循环几个 SQL 查询将不起作用。
    • 他/她创建了一个方法(Sub ConnectSQLServer),它是一个方法或子例程,而不是一个函数。让我们假设他/她将创建一个函数 (UDF) 并从该函数调用 ConnectSqlServer 方法,嗯....我认为这是一个坏主意,因为代码运行速度很慢。
    • 是的,我只想提取一个值。考虑一个包含 500 家美国公司的财务数据的表格。列名称是 Ticker(主键)、Year、Revenue、Costs、Profit.. 假设如果我想为 Apple Inc. 提取 2015 年的收入,我将使用 (SELECT Revenue FROM WHERE Ticker ='AAPL',年 = '2015')。所以它只会返回一个值(即收入数字)...我正在尝试创建一个类似于 GetCompanyData(,).. 的 excel 函数
    • @CheriesMewengkang 就像我想的那样:他/她想要一个 UDF 但还不知道。一旦他/她意识到volatile 代表什么,他/她可能也想要那个。因此,此插件将需要一个recalculate 按钮,该按钮会扫描整个 Excel 文件中是否出现任何 UDF,将所有这些 SQL 调用预先聚合为一个,然后将其全部传递给 SQL。之后查询的结果(从服务器返回)必须单独传回所有函数。这是一个巨大的工程!因此,我将标记关闭这篇文章,因为它过于宽泛。
    • @Ralph 感谢您解释这件事的严重性。您认为这在 VBA 中可行吗?嘿,这是 Jayanth 顺便说一句,所以它的“他”:)
    【解决方案2】:

    在这种情况下,不要在循环中执行 db 操作。这是耗时且不正确的使用。相反,在一个循环中创建 select、insert 或任何语句,然后对循环操作和计算进行编译,然后只打开一次连接并将请求(创建的 sql 脚本)发送到 db 并从 db 获取响应,然后关闭连接。就这样。 db 操作必须与日常操作和递归操作分开。(反模式)最好的问候。

    【讨论】:

      【解决方案3】:

      免责声明:虽然这不是帖子中描述的问题的直接解决方案,但我想将此方法添加为对所描述问题的更快、更简单的解决方案。

      第 1 步:创建一个(可能是隐藏的)工作表,您可以在其中提取此 Excel 文件中所需的所有 SQL 数据。将数据拉入具有所有必要列/维度的一个表中,以便之后从该表中获取数据。

      这就是我的意思。假设您在这个 Excel 文件中需要 SQL 服务器上表 Users 中的一些数据以及服务器上 StockMarket 表中的一些信息。从表Users 中,您需要用户ID、名字、姓氏和职位。在StockMarket 表中,您将需要股票市场 ID 和该特定股票的价格。由于这些价格是按日期计算的,因此您还需要价格的报价日期。

      现在,既然您希望所有数据都在一个表中,您必须想出一种聪明的方法来将所有这些数据合并到一个表中。一种方法可能如下:

      之后,您可以使用以下查找函数从上表中获取所有数据:

      =INDEX(SQLdata,MATCH(1,(SQLdata[Table]="Users")*(SQLdata[UserID]=25),0),4)
      

      请注意,我将表命名为 SQLdata,以便在查看和理解公式时更容易。此外,像这样,您可以轻松扫描 Excel 文件以查找对该表的任何引用。

      另一种方法可以使表格更简洁:

      请注意,这次我将StringsNumbers 以及StringsDates 混合使用(这是非常糟糕的设计,对于这里的某些人来说甚至无法想到)。此外,列标题现在不太具有描述性。然而,这也有效:

      =INDEX(SQLrev,MATCH(1,(SQLrev[Table]="Users")*(SQLrev[Dimension1]=25),0),5)
      

      注意,我这次调用的是表 SQLrev。

      这两种解决方案还允许您从表中聚合数据。因此,如果您想要(例如)Apple 在 2017 年的平均价格,那么您可以使用以下公式将今年的报价相加并除以 3:

      =SUM(IF("StockMarket"=SQLrev[Table];1;0)*IF("AAPL"=SQLrev[Dimension1];1;0)*SQLdata[Price])/3
      

      这种方法最显着的优势是您只需更新整个 Excel 文件中的一个表,这意味着只有 一个来自服务器的 SQL 拉取。

      最显着的缺点(除了编写起来可能相当复杂的 SQL 选择之外)是您需要知道需要驻留在此表中的所有数据。如果未将数据拉入此表,则上述公式都无法检索这些值。

      虽然这种方法肯定有其缺点,但它比您的目标 Excel 插件更容易实现。

      以上所有公式都是数组公式,必须按Ctrl + Shift + Enter 输入。有关数组公式的更多信息,请阅读以下内容:https://support.office.com/en-us/article/Guidelines-and-examples-of-array-formulas-7D94A64E-3FF3-4686-9372-ECFD5CAA57C7

      【讨论】:

      • @user626994 虽然完全可以按照您的描述编写这样的插件,但上述解决方案更容易实现,并且不需要 VBA 知识。所以,也许这个解决方案在这一点上更适合你。
      猜你喜欢
      • 2012-06-05
      • 1970-01-01
      • 1970-01-01
      • 2015-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多