【问题标题】:SQL Query to VBA Array对 VBA 数组的 SQL 查询
【发布时间】:2016-08-10 13:27:40
【问题描述】:

正如标题所示,我正在研究将查询内容存储到数组中的不同方法。我一直在尝试不同的方法来做这件事,但似乎这些方法中的大多数在它们的输出中都是正确的。这当然是因为我对如何适当地完成这一点缺乏了解,所以经过一段时间的试验,我决定问什么是最好的方法?到目前为止,我将与您分享我的一些方法,您可以看到我的调查在哪里找到了我。

Dim MyArray() As Variant
MyArray = rst.GetRows(rst.RecordCount)

这是ok,但这会将所有信息垂直而不是水平存储。有没有办法翻转它?那会是通过使用 ReDim 吗?或者这是因为行存储在数组维度中,因此它们自然是垂直的?

        Index = 0
        Do While Not rst.EOF
                ReDim Preserve MyArray(1, Index)
                MyArray(0, Index) = CStr(rst.Fields(0).Value)

                'Safety check to make sure the value isn't null (was having problems before)
                If rst.Fields(1).Value <> vbNullString Then
                    MyArray(1, Index) = CStr(rst.Fields(1).Value)
                End If
            Index = Index + 1
            rst.MoveNext
        Loop

        sheet.Range("a1:ba10000").Value = MyArray

这再次垂直存储了东西,但没有正确输出记录,实际上只提取每条记录的前两列信息,其余的输出为#N/A#。我认为我更接近我最初的方法,但我决定进行实验可能会让我找到某个地方。

你有什么建议或者可以指出我正确的方向吗?

【问题讨论】:

    标签: sql arrays excel recordset vba


    【解决方案1】:

    我认为将结果转储到工作表会更快:

    Sheet1.Range("A1").CopyFromRecordset rst
    

    然后将该转储的结果(来自范围)存储到一个数组中。如果它不是您喜欢的垂直或水平,快速复制/粘贴特殊转置将在将其放回数组之前快速处理它。

    我只是建议,因为您的记录集似乎相当大(2x10000),所以在您进行迭代时将非常耗时,将结果转储到工作表、操作并重新拾取它们应该很快。


    更新(多年后)。看起来可以转储到数组中。比如:

    Dim arr
    rst.MoveFirst
    arr = rst.GetRows
    

    这将允许在将数据输出到工作簿之前对记录集(在数组中)进行编程操作。

    【讨论】:

    • 看我以前是这样做的,现在我正处于实验阶段,我试图提高性能,但你让它听起来像“6 of one,half-打其他”的交易offs 真的不算多。
    • 将记录集转储到工作表中,进行操作,然后将其重新拾取到您的数组中以执行您要执行的任何其他操作,似乎有点笨拙,但是...您的结果集是大,范围内的数据转换是 Excel...擅长的...所以我就让它做它的事情。
    • 我使用 ADODB 是因为我连接到 Teradata(有时连接到 SQLServer,并且每隔一段时间连接到一个 excel 表),这让我感觉很舒服。它速度快,支持良好,感觉更像是 Access 之外的标准,通过 vba 查询 Access。我同意我们的代码看起来非常相似。我只是想在这里举一个例子,它显示了一个记录集被放到工作表中,被操纵,然后被推到一个数组中。这是一个有趣的例子,其中有很多方法可以做需要做的事情:)
    • @JohnShaw 自从我使用 ADODB 记录集以来已经有好几年了,尽管我认为我的组织中仍然有一些工作簿。您是否有一种可靠的方法将结果集转储到 VBA 中的数组中?如果是这样,我认为这将是对这个问题的一个很好的回答。我同意转储到工作表范围然后进行操作肯定感觉不对,我只是从未找到将ADODB.resultset 对象转换为数组、集合或字典的更好方法。我必须认为有一种方法可以在不迭代结果集的情况下做到这一点。
    • @JohnShaw 我在网上做了一些挖掘工作,并建议使用ADODB.Recordset 对象的.GetRows() 方法将其转储到数组中,这似乎可以解决问题。我今天在mac上没有测试过,但感觉它应该可以工作。我已经更新了答案以包括在内。
    【解决方案2】:

    这应该可以回答您的问题,尽管晚了 5 年。 记录集数组工作表

    ReDim Preserve 只能用于调整上一个维度的上限。您还没有 1,所以没有 ReDim Preserve。

    'Goes on Top
    Option Explicit
    Option Compare Text
    Option Base 1
    
    Public Sub Recordset_to_Array_to_Worksheet()
    
    Dim MyArray() As Variant 'unbound Array with no definite dimensions'
    Dim db as DAO.Database
    Dim rst as DAO.Recordset
    Dim strSQL as String, Fieldname as String
    Dim i as Integer, j as Integer, colcnt as Integer, rowcnt as Integer
    Dim wb as Workbook
    Dim ws as Worksheet
    Dim Dest as Range
    
    '------------------------RECORDSET------------------------'
    Set db = Opendatabase("URL link") 'or Set db = Currentdb()
    strSQL = "SQL Statement Here"
    
    Set rst = db.OpenRecordset(strsQL, dbOpenDynaset)
    
    If rst.recordcount <> 0 then '///Do NOT Use "Do While Not rst.EOF" Can cause Problems///'
        colcnt = rst.Fields.Count-1
        rowcnt = rst.recordcount
     Else
        Exit Sub
    End IF
    
    '-----------------------------WRITE RECORDSET TO MYARRAY----------------------------'
    ReDim MyArray (rowcnt, colcnt) 'Redimension MyArray parameters to fit the SQL returned'
    rst.MoveFirst
    
    'Populating Array with Headers from Recordset'
    For j = 0 To colcnt
         MyArray(0,j) = rst.Fields(j).name
    Next
    
    'Populating Array with Record Data
    For i = 1 to rowcnt
        For j = 0 to colcnt
            MyArray(i,j) = rst(j)
        Next J
        rst.movenext
    Next i
    
    '---------------------------------WORKSHEET OUTPUT---------------------------------'
    Set wb = ThisWorkbook
    Set ws = wb.Worksheets("Insert Worksheet Name")
    Set Dest = ws.Range("A1") 'Destination Cell
    Dest.Resize(UBound(MyArray, 1) + 1, UBound(MyArray, 2) + 1).value = 
    Application.Transpose(MyArray) 'Resize (secret sauce)
    
    End Sub
    

    【讨论】:

    • 在发布到工作表的半永久性之前,经常需要将记录集拉入数组框架,因为需要对数据进行进一步的转换或操作。对我来说,过去的示例包括:为返回的数据构建 30、60、90、120 个老化桶;将数十个银行账户的金额报告到特定类别中;或者,创建一个数组以根据时序报告 amts。所有这些都需要在工作表输出之前完成。这是个好问题。
    • 很高兴看到这么多年后这个问题仍然不时引起注意。我也喜欢看看我当时在哪里,我成长了多少,太酷了!尽管如此,我不记得我在为这个 LOL 做什么项目
    • @DougCoats - 我和你在一起。回去看看你已经走了多远感觉真的很好。我不认识你,但无论如何我为你感到骄傲。
    • 这是对问题的一个很好的补充。看起来这里需要遍历记录集对象来填充数组。我怀疑有一点记录集的大小使得这比转储到工作表然后将范围转换回 VBA 数组以进一步操作要慢。转储到隐藏的工作表,转换为数组,清除后台工作表,然后操作可能会更快。
    • 当我这些天写 vba 时(我不需要像以前那样多,我现在大部分时间都卡在 sql server 中,哈哈),数组几乎是默认行为。事实上,我会说与特定应用程序的对象模型进行不必要的交互是 VBA 编程的主要罪恶。不过,当我最初问这个问题时,我没有完全意识到的一件事是 getrows() 默认转置数组,我仍然不知道为什么(我认为这是为了使编写新记录更容易)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-24
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2017-11-02
    相关资源
    最近更新 更多