簡體   English   中英

如何在VBA中實現SQL Group By語句

[英]How to implement a SQL Group By statement in VBA

我正在嘗試在VBA中實現SQL Group By語句。 我有一個簡單的工作表,其中有4列(login_year,login_month,login_day,user_name),並且我想產生一個每月登錄的唯一用戶數。

因此,Oracle SQL將是:

SELECT 
login_year, 
login_month, 
COUNT(DISTINCT user_name) 
FROM users
GROUP BY 
login_year, 
login_month;

如何最好使用VBA來實現這一點?

非常感謝您的幫助。

您需要設置對MS腳本庫的引用才能訪問Dictionary對象。

下面的代碼為每年/每月創建一個字典條目。 然后,每個條目都擁有另一個有關名稱的字典。 子詞典的計數是唯一計數。

Sub ListDistinctUserCount()

    Dim vaValues As Variant
    Dim dc As Scripting.Dictionary
    Dim dcNames As Scripting.Dictionary
    Dim i As Long
    Dim sAllData As String

    'read range into array
    vaValues = Sheet1.Range("A2:D51").Value
    Set dc = New Scripting.Dictionary

    For i = LBound(vaValues, 1) To UBound(vaValues, 1)
        'concat the year and month for dictionary key
        sAllData = vaValues(i, 1) & "|" & vaValues(i, 2)

        'if it's already added
        If dc.Exists(sAllData) Then
            'add the name if it doesn't exists
            If Not dc.Item(sAllData).Exists(vaValues(i, 4)) Then
                dc.Item(sAllData).Add vaValues(i, 4), vaValues(i, 4)
            End If
        Else
            'otherwise add the year month and a new dict for the names
            Set dcNames = New Scripting.Dictionary
            dcNames.Add vaValues(i, 4), vaValues(i, 4)
            dc.Add sAllData, dcNames
        End If
    Next i

    For i = 0 To dc.Count - 1
        Debug.Print dc.Keys(i), dc.Items(i).Count
    Next i

End Sub

不是很優雅,但是我想不出更好的方法。

VBA新手的其他信息

Variant數據類型可以包含任何其他數據類型。 它很大且效率最低,但是在某些情況下是必需的。

多像元范圍的Range.Value屬性返回一個二維的,基於一的數組。 您可以將該數組分配給Variant並循環遍歷。 這比讀取單個單元格快得多。 眾所周知,讀取和寫入Excel網格的速度很慢,因此將整個范圍讀入數組並以這種方式處理數據是一種常見的做法。

VBA具有用於存儲數據的Collection對象。 Scripting.Dictionary對象具有一些使它優越的功能,例如.Exists屬性,並將所有鍵或項寫為數組。 默認情況下,腳本庫與Office一起安裝,但默認情況下不包含在新項目中。 您必須轉到“工具-參考”,然后將其包括在內。

字典是關鍵項目列表,就像您在許多其他語言中找到的一樣。 該項目幾乎可以是任何數據類型。 在這種情況下,該項目是另一個詞典。

與其他RDMS相比,雖然Jet / ACE SQL引擎(用於MS Office / Windows程序,包括Access,Excel)使用的方言與其他RDMS相比不維護COUNT(DISTINCT ...) ,但是您可以使用派生表首先按月返回唯一用戶,年,然后在外部查詢中對其進行計數。

SQL (嵌入在下面的字符串中)

SELECT u.login_year, u.login_month, COUNT(*) As usercount
FROM 
   (SELECT user_name, login_year, login_month 
    FROM users
    GROUP BY user_name, login_year, login_month) As u
GROUP BY u.login_year, u.login_month;

VBA (ADO驅動程序/提供程序連接)

Sub RunSQL()    
    Dim conn As Object, rst As Object
    Dim strConnection As String, strSQL As String
    Dim i As Integer

    Set conn = CreateObject("ADODB.Connection")
    Set rst = CreateObject("ADODB.Recordset")

    ' CONNECTION STRINGS (TWO VERSIONS)
'    strConnection = "DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" _
'                      & "DBQ=C:\Path\To\Workbook.xlsm;"
    strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" _
                       & "Data Source='C:\Path\To\Workbook.xlsm';" _
                       & "Extended Properties=""Excel 8.0;HDR=YES;"";"

    strSQL = " SELECT u.login_year, u.login_month, COUNT(*) As userCount " _
                & " FROM " _
                & "   (SELECT user_name, login_year, login_month " _
                & "    FROM users" _
                & "    GROUP BY user_name, login_year, login_month) As u" _
                & " GROUP BY u.login_year, u.login_month;"                    
    ' OPEN DB CONNECTION
    conn.Open strConnection
    rst.Open strSQL, conn

    ' COLUMN HEADERS
    For i = 1 To rst.Fields.Count
        Worksheets("RESULTS").Cells(1, i) = rst.Fields(i - 1).Name
    Next i        
    ' DATA ROWS
    Worksheets("RESULTS").Range("A2").CopyFromRecordset rst

    rst.Close: conn.Close    
    Set rst = Nothing: Set conn = Nothing    
End Sub

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM