菩薩慈悲:菩薩您的表格是Excel還是MS Word?還是其他呢?
用VBA的話,就用 Scripting.Dictionary,在VB.NET的話,則應有類似且效能更好的Dictionary來實作,很容易的。若需詳情,俟覆再議。感恩感恩 南無阿彌陀佛
昨天才在iT邦幫忙收到 IT 邦邦友大師菩薩的指點,才知道用Dictionary的效能較 ADO、SQL 差太多,
我用 3 萬筆資料測試結果如下:
1.Access : 不超過 1 秒
2.Excel +VBA + SQL (未上色) : 12 秒
3.Excel +VBA + SQL (上色) : 17 秒
4.Excel +VBA (你的) : 2 分 35 秒
因此先改用ADODB 與 OLEDB 實作看看。
ps.以下程式碼在測試對象檔案開啟時是可以測試成功的。
Microsoft.Jet.OLEDB.4.0 要用 .xls 而 Microsoft.ACE.OLEDB.12.0 才能用 .xlsm .xlsx .xlsb …… 在不開啟原檔時,才不會出錯。
Sub sumbyNameGroup()
' 設置讀取檔案路徑及連線字串
Dim filePath As String = "C:\Users\ssz3\Documents\t.xlsb" '"your_excel_file_path"
Dim sheetName = "工作表1"
'Dim connString As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filePath + ";Extended Properties=Excel 12.0;"
Dim connString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Excel 8.0;Database=" + filePath
Dim conn As New ADODB.Connection
conn.Open(connString)
' 構建 SQL 語句,選擇要操作的工作表及數據欄位
Dim sqlStr As String = "SELECT 姓名, SUM(成績1) AS 成績1總和, SUM(成績2) AS 成績2總和 FROM [" + sheetName + "$] GROUP BY 姓名"
Dim rst As New ADODB.Recordset
rst.Open(sqlStr, conn)
' 輸出結果
Do Until rst.EOF
Console.WriteLine(rst.Fields("姓名").Value + " " +
rst.Fields("成績1總和").Value.ToString() + " " +
rst.Fields("成績2總和").Value.ToString())
'Console.WriteLine(rst.Fields(0).Value + " " +
' rst.Fields(1).Value.ToString() + " " +
' rst.Fields(2).Value().ToString())
rst.MoveNext()
Loop
rst.Close() : conn.Close()
End Sub
或
Sub sumbyNameGroup()
' 設置讀取檔案路徑及連線字串
Dim filePath As String = "C:\Users\ssz3\Documents\t.xlsb" '"your_excel_file_path"
Dim sheetName = "工作表1"
'Dim connString As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filePath + ";Extended Properties=Excel 12.0;"
Dim connString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Excel 8.0;Database=" + filePath
' 創建 OleDbConnection
Dim conn As System.Data.OleDb.OleDbConnection = New System.Data.OleDb.OleDbConnection(connString)
' 構建 SQL 語句,選擇要操作的工作表及數據欄位
Dim sqlStr As String = "SELECT 姓名, SUM(成績1) AS 成績1總和, SUM(成績2) AS 成績2總和 FROM [" + sheetName + "$] GROUP BY 姓名"
' 創建 OleDbDataAdapter
Dim da As System.Data.OleDb.OleDbDataAdapter = New System.Data.OleDb.OleDbDataAdapter(sqlStr, conn)
' 創建 DataTable 物件
Dim dt As DataTable = New DataTable()
' 執行 SQL 查詢並將查詢結果填充到 DataTable
da.Fill(dt)
' 關閉資源
da.Dispose()
conn.Dispose()
' 輸出結果
For Each row As DataRow In dt.Rows
Console.WriteLine(row("姓名").ToString() + " " + row("成績1總和").ToString() + " " + row("成績2總和").ToString())
Next
End Sub
而若要參考ADODB組建,則須將其「內嵌Interop類型」屬性設成 False,如圖:
您可以使用 Excel Interop 或者使用第三方库如 ClosedXML 或 EPPlus。下面是使用 ClosedXML 的示例代码:
首先,您需要在项目中安装 ClosedXML NuGet 包。然后,可以按照以下代码示例来读取 Excel 表格并进行统计:
Imports ClosedXML.Excel
' 打开 Excel 文件
Using workbook As New XLWorkbook("YourExcelFile.xlsx")
' 选择要读取的工作表
Dim worksheet As IXLWorksheet = workbook.Worksheet("Sheet1") ' 替换为实际的工作表名称
' 创建一个字典来存储姓名和对应的成绩
Dim scores As New Dictionary(Of String, Integer())
' 获取姓名和成绩列的索引
Dim nameColumnIndex As Integer = 1 ' 姓名所在列的索引(假设为第1列)
Dim score1ColumnIndex As Integer = 2 ' 成绩1所在列的索引(假设为第2列)
Dim score2ColumnIndex As Integer = 3 ' 成绩2所在列的索引(假设为第3列)
' 遍历表格的每一行(从第2行开始,跳过标题行)
For row = 2 To worksheet.RowsUsed().Count()
' 获取姓名和成绩
Dim name As String = worksheet.Cell(row, nameColumnIndex).Value.ToString()
Dim score1 As Integer = worksheet.Cell(row, score1ColumnIndex).GetValue(Of Integer)()
Dim score2 As Integer = worksheet.Cell(row, score2ColumnIndex).GetValue(Of Integer)()
' 如果姓名在字典中不存在,则添加一个新的项
If Not scores.ContainsKey(name) Then
scores.Add(name, New Integer() {score1, score2})
Else
' 如果姓名已经存在,则将成绩累加到已有的项中
scores(name)(0) += score1
scores(name)(1) += score2
End If
Next
' 输出每个姓名对应的成绩总和
For Each kvp As KeyValuePair(Of String, Integer()) In scores
Dim name As String = kvp.Key
Dim totalScore1 As Integer = kvp.Value(0)
Dim totalScore2 As Integer = kvp.Value(1)
Console.WriteLine("姓名: " & name)
Console.WriteLine("成绩1总和: " & totalScore1)
Console.WriteLine("成绩2总和: " & totalScore2)
Console.WriteLine()
Next
End Using