在Excel VBA中寫SQL,是一種什麼體驗

  每每提到Excel辦公自動化,我們腦海裏能想到的就是公式、數據透視表、宏、VBA,這也是我們大部分人數據分析的進階之路。當我們對於常用VBA技巧已經相當熟練後,往往會有一種“我的VBA知識夠用啦”的錯覺,其實那只是因爲我們收到的實際需求還不夠複雜和多樣化。

 

 

  一旦哪天碰到略顯複雜的業務需求時,我們才知道VBA變量、循環、條件判斷、數組、字典、窗體,這些還只是VBA的基礎知識罷了,會了這些,遠達不到【蒂花之秀】的水準。我們今天的主角,SQL(結構化查詢語言),通過嵌入VBA代碼中,就可以解決很多複雜的實際問題。

  考慮到寫VBA的大軍主要還是辦公人員,如財務崗、行政崗,並非科班程序員出身,他們往往覺得SQL是後端程序員才使用的語言,並不那麼容易掌握,其實這不過是另一種認知的偏差。我們今天就通過一個簡單例子,看看在VBA中如何寫SQL,是一種什麼體驗。

 

  想要在VBA中使用SQL,我們就不得不先認識下ADO。

ADO,其實是ActiveX Data Objects的簡稱,說人話,它其實是幾個ActiveX對象(類),用於提供數據(Data)之間的訪問;

Connection:ADO Connection 對象用於創建一個訪問某個數據源的開放連接。基於此開放連接,我們可以對一個數據庫進行訪問和相關操作;

Recrodset:ADO Recordset 對象用於存儲一個來自數據庫表的記錄集。一個 Recordset 對象由記錄和列(字段)組成。它也是我們最常用的操作數據庫的對象。

  我們數據庫的數據源(dataSource)可以是Access、SQL Server、Oracle 等數據庫,也可以是簡單的text文件,甚至可以是一個excel文件。考慮到辦公人員的主要數據來源都是excel文件,我們先來看看如何連接excel文件作爲我們的數據源。

 

03版本Excel(.xls)

Provider=Microsoft.jet.OLEDB.4.0;Extended Properties=’Excel 8.0;HDR=yes;IMEX=0’;Data Source=帶路徑的Excel工作簿完整名稱;

 

07~19版本Excel(.xlsx 或.xlsm)

Provider=Microsoft.ACE.OLEDB.12.0;Extended Properties=’Excel 12.0; HDR=yes;IMEX=0’;Data Source=帶路徑的Excel工作簿完整名稱。

 

如何理解【Data Source=帶路徑的Excel工作簿完整名稱】這句話?

  翻譯成程序語言,就是要這個文件的完整路徑,如果我們要控制的數據源就是我們當前的xlsm宏文件,那麼就是Data Source=thisworkbook.FullName,如果是同目錄下某個'test.xlsx'文件,我們則可以寫作:Data Source=thisworkbook.path &"\test.xlsx"。

  有了這些基礎知識,我們還需要知道SQL的一些基礎語法,此處推薦SQL 教程 (w3school.com.cn) 進行入門。

現在我們就可以使用SQL Select語句做一個最基礎的查詢了。

 

場景一:利用SQL將【表一】數據拷貝到【表二】

 

 代碼如下:

 1 Sub myFirstQuery()
 2     '將表一的數據查詢到後,返回到表二中,包含字段名
 3     Dim CONN As Object, sht As Worksheet, RS As Object, i As Integer
 4     Set CONN = CreateObject("ADODB.Connection")
 5     Set sht = ThisWorkbook.Sheets("表二")
 6     CONN.Open "provider=Microsoft.Ace.oledb.12.0;Extended Properties=Excel 12.0;data source=" & ThisWorkbook.FullName
 7     Sql = "SELECT *  FROM [表一$]"  '查找表一的所有數據,*默認指查找所有字段內容
 8     Set RS = CONN.Execute(Sql)
 9     
10     For i = 0 To RS.Fields.Count - 1 '輸出字段名,也就是excel列名,索引從0開始,而Excel行列索引號均從1開始計數
11         sht.Cells(1, i + 1).Value = RS.Fields(i).Name
12     Next
13     sht.Cells(2, 1).CopyFromRecordset RS '將查詢到的recordset數據集粘貼到表二的A2單元格
14     CONN.Close
15 End Sub

 

場景二:篩選【表一】中 姓名爲‘溫寧’的數據到【表二】中

其實,有了sql基礎,我們只需要對上面的SQL代碼加上Where條件判斷子句即可。

 

代碼如下:

 1 Sub myFirstQuery()
 2     '將表一的數據查詢到後,返回到表二中,包含字段名
 3     Dim CONN As Object, sht As Worksheet, RS As Object, i As Integer
 4     Set CONN = CreateObject("ADODB.Connection")
 5     Set sht = ThisWorkbook.Sheets("表二")
 6     CONN.Open "provider=Microsoft.Ace.oledb.12.0;Extended Properties=Excel 12.0;data source=" & ThisWorkbook.FullName
 7     Sql = "SELECT *  FROM [表一$] WHERE 姓名='溫寧'"  '查找表一中姓名='溫寧'的所有數據
 8     Set RS = CONN.Execute(Sql)
 9     
10     For i = 0 To RS.Fields.Count - 1 '輸出字段名,索引從0開始,而Excel行列索引號均從1開始計數
11         sht.Cells(1, i + 1).Value = RS.Fields(i).Name
12     Next
13     sht.Cells(2, 1).CopyFromRecordset RS '將查詢到的recordset數據集粘貼到表二的A2單元格
14     CONN.Close
15 End Sub

 

  通過以上兩個場景不難看出,核心的邏輯只需要一句SQL就足以,SQL並不是什麼程序員才能掌握的東西,我們完全不用擔心無法掌握它。不過我們每次使用前都要提前定義CONNECTION、RECORDSET等對象,包括輸出字段名等必要操作。因此,當如果我們的業務足夠簡單時,使用VBA中的基礎功能反而寫起來更快,當業務邏輯複雜時,我們纔會重點考慮SQL,永遠不用爲了用SQL而刻意寫SQL。用對了地方,SQL就是六脈神劍;用錯了地方,就真成了花裏胡哨的炫技,Duck不必。

歡迎掃碼關注我的公衆號 獲取更多爬蟲、數據分析的知識!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章