[英]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.