# **EXCEL VBA** <i class="fa fa-book fa-fw"></i> 查看排版(因為結束語法要End) --- https://www.onlinegdb.com/online_vb_compiler 基本功能 --- ## 架構 Project(專案)**(通常為使用中的excel)** <br> | <br> --> 模組 <br> &emsp; | <br> &emsp;--> Sub <br> ## 基本指令 ### sub ``` Visual Basic for Applications= Sub 基本指令() '在此輸入指令註解 在此輸入指令 end Sub ``` ### 為Module命名 > 此code為txt檔可見 <br> ``` Visual Basic for Applications= Attribute VB_Name = "Module2" ``` ▼一般作法:在屬性中更改資料,如下紅標所示<br> ![](https://i.imgur.com/3XXZUHv.png) ### Define variable: Dim & Set > Dim: 可在sub外執行,同一個Module下可共用變數,**不指定type時為Varient** <br> ``` Visual Basic for Applications= Dim var1 As Integer var1 = 1 Dim var2 As String var2 = "my name is var2" Dim var3 As Double var3 = 2.34567 ``` > Set: 定義物件時使用,需在Sub內執行,**變數仍需定義(不知道型態時可定義為Varient)** ``` Visual Basic for Applications= Dim xDlg As FileDialog Set xDlg = Application.FileDialog(msoFileDialogFolderPicker) ``` ### 印出(crlt+G顯示及時運算視窗) ``` Visual Basic for Applications= Debug.Print var1 & "," & var2; var3 ``` ### 跳視窗 >建議參考微軟官方文件再依個人需求調整:https://learn.microsoft.com/zh-tw/office/vba/language/reference/user-interface-help/msgbox-function <br> ``` Visual Basic for Applications= MsgBox var1 ``` ### Msgbox、inputbox等其他程式換行指令:vbCrLf ``` Visual Basic for Applications= MsgBox r1.Row & "," & r1.Column & vbCrLf & r2.Row & "," & r2.Column ``` ### 輸入值 ``` Visual Basic for Applications= start_col = InputBox("起始欄在?", "起始欄", "A") '出來是字串 ``` ### 輸入公式 >範例指向欄位的方式為絕對路徑,另有相對路徑,參考錄製巨集結果。 ``` Visual Basic for Applications= Range("B1").FormulaR1C1 = "=COUNT(R3C3:R150C3)-1" ``` ### 選出空白儲存格並填滿 >Selection.SpecialCells(xlCellTypeBlanks).Select ``` Visual Basic for Applications= Range("A4:Z4").Select Selection.SpecialCells(xlCellTypeBlanks).Select Selection.FormulaR1C1 = "=R[-1]C" ``` ### 內建公式:sum ``` Visual Basic for Applications= dim s s = WorksheetFunction.Sum(Range("F2:F10")) ``` ## 顏色 ### 儲存格顏色填入1: RGB法 ``` Visual Basic for Applications= With Cells(1, 1) '在A1下 .Value = "RGB(" & 170 & "," & 225 & "," & 10 & ")" .Interior.color = RGB(170, 225, 10) End With ``` > ![image](https://hackmd.io/_uploads/H1Ht2UiVR.png) ### 常用顏色 ``` RGB(170,225,10) '綠 RGB(225,5,60) '紅 RGB(225,75,10) '橘 RGB(115,225,14010) '淡藍 RGB(105,120,9300) '深藍 RGB(225,190,20240) '淡紫 RGB(225,225,10) '土黃 ``` > ![image](https://hackmd.io/_uploads/SJW6nLoE0.png) ### 判斷式系列 ### 範例:調成數字,順便設個取消 > 用IsNumeric()搭配if進行判斷,注意If式若有換行,需有End If做結束 ``` Visual Basic for Applications= If IsNumeric(start_col) = False Then start_col = Range(start_col & 1).Column ElseIf srart_col = "" Then End End If ``` ### 解除合併儲存格 ``` Visual Basic for Applications= Selection.UnMerge ``` ### 插入列 ``` Visual Basic for Applications= Columns("A:A").Select Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove ``` ### 指定本活頁簿 ``` Visual Basic for Applications= ThisWorkbook.Activate ``` >ThisWorkbook下其他物件,適合變成變數 ``` Visual Basic for Applications= ThisWorkbook.Name ThisWorkbook.Path ```` > <font color = Red>**皆可搭配"\檔名.副檔名"做存檔**</font> ### 切換至其他活頁簿 ``` Visual Basic for Applications= Windows("活頁簿1.xlsx").Activate ``` ### 工作表 >選取工作表 <br> 1. 以工作表名選取 <br> ``` Visual Basic for Applications= Sheets("工作表1").Select ``` 2. 以工作表位置選取 <br> ``` Visual Basic for Applications= Sheets(1).Select ``` >當前工作表 ``` Visual Basic for Applications= ActiveSheet.Select ActiveSheet.Name ``` > 新增新活頁簿 ``` Visual Basic for Applications= Workbooks.Add ``` ### 工作表總數 ``` Visual Basic for Applications= Worksheets.Count ``` ### 工作表列總數 ``` Visual Basic for Applications= ActiveSheet.UsedRange.Rows.Count '該工作表列總數,反之行換成column ``` ### If以外的選擇:select case >在做依變量改變成幾種情況(字串或數字皆可)時可以使用,以下範例: Select Case Sheets.Count Case 5 MsgBox "不用刪喇" Case 28 MsgBox "表數過多,要刪喔" For i = 2 To Sheets.Count - 4 Sheets(2).Select > 以string做辨別+Case Else的用法: ``` Visual Basic for Applications= For i = 2 To Range("A2").End(xldown).row Select Case Cells(i, 2).Value Case 小明 MsgBox "叫小明的資料不用刪" Case Else Cells(i, 2).Value MsgBox "其他的資料須刪除" '刪除工作表 ActiveWindow.SelectedSheets.Delete Next '迴圈結尾 Application.DisplayAlerts = True Case Else End End Select 'Select結尾 ``` >▲只有sheet.count是5或28時才有執行程式,其他不會執行 ### 使警告視窗關閉,不會跳出警報 > excel vba限定的樣子,其他office vba可以執行此指令,但沒有效果 Application.DisplayAlerts = False ### 開啟警告 Application.DisplayAlerts = True ### 刪除列 > 範例:第一列刪掉 Rows(1).EntireRow.Delete #### 另存新檔 > 令存為xlsx ActiveWorkbook.SaveAs Filename:= _ ActiveWorkbook.Path & "\檔名.副檔名" _ , FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False #### 儲存格填值 > 1. 使用Range物件 Range("A1").Value = "A1的值" > 2. 使用Cells物件 Range(1,1).Value = "A1的值" ### 選取儲存格 Range("A1").Select ### offset:現有格子移動 >Note: Selection = 現在選的儲存格 >往右一格 Selection.offset(0, 1).Select >往下一格 Selection.offset(1, 0).Select ### 求筆數/行數,並存成變數 > Row: 指定儲存格之列 Row = Range("A1").End(xlDown).Row >Column: 指定儲存格之行 ``` Visual Basic for Applications= Col = Range("A1").End(xlToRight).Column ``` ### 其他End()指令 > 有UP、Down、Left、Rigt等,相當於Crlt+方向鍵 ``` Visual Basic for Applications= Range("A1").End(xlToLeft).Select Range("A1").End(xlToUp).Select ``` ### copy & paste >**copy** ``` Visual Basic for Applications= Range("I4").Select Range(Selection, Selection.End(xlDown)).Select Range(Selection, Selection.End(xlToRight)).Select Selection.Copy Range("B2").Select ``` >**貼上值 ** ``` Visual Basic for Applications= Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _ :=False, Transpose:=False ``` >**純貼上** ``` Visual Basic for Applications= Range("B2").Select ActiveSheet.Paste ``` ### 所有格線精簡版 Range("A2:D29").Select Selection.Borders.LineStyle = xlContinuous ### 欄寬自動調整 ``` Visual Basic for Applications= Range("E3:I3").Columns.AutoFit ``` ### 跳過error繼續執行 >迴圈裡會跳過執行迴圈 ``` Visual Basic for Applications= On Error Resume Next ``` ### 樞紐分析表 >soucedata若為外部連結格式為:[主檔案名]工作表名!R(列數編號)C(行數編號):R(列數編號)C(行數編號) ``` Visual Basic for Applications= ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:= _ ThisWorkbook.Path & "\" & 活頁簿 & 工作表 & "!R1C1:R" & Row & "C" & Col, Version:= _ xlPivotTableVersion15).CreatePivotTable TableDestination:=title(i) & "!R1C9", _ TableName:="樞紐分析表" & i, DefaultVersion:=xlPivotTableVersion15 ``` ### 樞紐篩選的選取方式:PivotItem > 範例:勾選所有年度 ``` Visual Basic for Applications= Dim PivotItem As PivotItem For Each PivotItem In ActiveSheet.PivotTables("樞紐分析表1").PivotFields("年度").PivotItems PivotItem.Visible = True Next PivotItem ``` ## 進階:表單 ### 顯示表單 >用sub呼叫 ```Visual Basic for Applications= # 表單變數名稱+show Userform1.Show ``` ### 進度條概念 1. 興建表單 2. 設置Lebel1, Lebel2,Frame1 3. Framr1顏色為藍色,放Lebel1裡面 4. 對表單右鍵>查看程式碼 5. 程式視窗上方有2個下拉式選單,分別選擇userform, initialize ,然後sub內設定Frame1出始長度為0、可視 6. 再選userform, activate,設定呼叫計算總進度的sub名稱 7. 模組內建立計算總進度的sub,計算總進度(通常看迴圈次數估)、累積進度、%值,將這兩個變數傳至主要作用的Sub裡 8. 主要作用的sub中每隔一段時間要計算累積進度跟%值,並回傳給另一個決定進度條長度的sub,程式大概長這樣 ```Visual Basic for Applications= Userform1.Lebel2.Caption =%數*100 & "%已完成" Userform1.Frame1.width = %數*初始設定長度 doevents ``` ## Sub 作品集 ### 關鍵字比對 > 1. 方法1: 製作VBScript.Reg物件 > 2. 方法2: 以instr()+Array迴圈尋找 ``` Visual Basic for Applications= Sub 關鍵字比對() Dim 關鍵字 As Object Dim temp, Str As String temp = "" Set 關鍵字 = CreateObject("VBScript.RegExp") Sheets("含有關鍵字的工作表").Select '關鍵字起始列至結束列 For i = 2 To 1719 temp = temp & Range("A" & i) & "|" Next i temp = "(" & temp & Range("A" & ActiveSheet.UsedRange.Rows.Count).Value & ")" '所有的關鍵字格式: "(A|B|C)" ,以此類推 Debug.Print temp 關鍵字.Pattern = temp Sheets("欲對照檔案").Select n = Range("a1").End(xlDown).Row For k = 2 To n '假設要測D欄 Str = Range("D" & k) If 關鍵字.test(Str) Then Debug.Print k & ":OK" Else Debug.Print k & ":" & Str End If Next k End Sub ``` > 方法2 ``` Visual Basic for Applications= Sub sol2() '另一種尋找關鍵字的方法,把要找的字串跟keyword都變成array會比較快 Dim key key = Array("要找的關鍵字") for i = 0 to 0 If InStr(1, Range("A1"), key, vbBinaryCompare) Then Debug.Print "OK" End If next i End sub ``` ### 分割資料 ``` Visual Basic for Applications= Sub 分割資料() Dim 副檔名, FilePath As String Dim 原始檔 As Workbook Dim xDlg As FileDialog Dim filefont, start_col, end_col, diff 副檔名 = "XXX" '設定副檔名,用陽春的if判定filefont要是甚麼屬性(後面會用到) Do Until 副檔名 <> "XXX" 副檔名 = InputBox("檔案要分割成甚麼檔?要輸入副檔名喔喔喔" & vbCrLf _ & "目前可用:xlsx、csv、ods、xls", "求副檔名", "xlsx") If 副檔名 = "csv" Or 副檔名 = ".csv" Then filefont = xlCSV ElseIf 副檔名 = "xlsx" Or 副檔名 = ".xlsx" Then filefont = xlOpenXMLWorkbook ElseIf 副檔名 = "ods" Or 副檔名 = ".ods" Then filefont = xlOpenDocumentSpreadsheet ElseIf 副檔名 = "xls" Or 副檔名 = ".xls" Then filefont = xlExcel8 ElseIf 副檔名 = "" Then '唯一逃出迴圈手段:什麼都不做按取消 End Else MsgBox "這個程式很陽春,不支援這個副檔名><" 副檔名 = "XXX" End If Loop '加點點 If Left(副檔名, 1) <> "." Then 副檔名 = "." & 副檔名 Set xDlg = Application.FileDialog(msoFileDialogFolderPicker) xDlg.Title = "請選擇分割檔案放置的資料夾" '選擇要輸出的資料夾,有選到就存成變數 If xDlg.Show <> -1 Then Exit Sub FilePath = xDlg.SelectedItems(1) & "\" ThisWorkbook.Activate start_col = InputBox("起始欄在?", "起始欄", "A") '調成數字,順便設個取消 If IsNumeric(start_col) = False Then start_col = Range(start_col & 1).Column ElseIf srart_col = "" Then End End If end_col = InputBox("最後一欄在?", "最後一欄", "B") '調成數字,順便設個取消 If IsNumeric(end_col) = False Then end_col = Range(end_col & 1).Column ElseIf end_col = "" Then End End If 'key幾筆資料 diff = InputBox("要幾筆資料為一個檔案?打數字喔", "幾筆", 2000) '變integer(整數)格式 diff = CInt(diff) For i = 2 To ActiveSheet.UsedRange.Rows.Count Step diff ThisWorkbook.Activate '選取位置 Range(Cells(i, start_col), Cells(i + diff - 1, end_col)).Select Selection.Copy Workbooks.Add ActiveSheet.Paste Application.CutCopyMode = False ActiveWorkbook.SaveAs filename:= _ FilePath & "第" & i & "列開頭" & 副檔名, FileFormat:=filefont, _ CreateBackup:=False '插表頭在第一列 Rows("1:1").Select Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove '原檔開啟、複製表頭 ThisWorkbook.Activate Cells(1, start_col).Select Range(Cells(1, start_col), Cells(1, end_col)).Select Selection.Copy '切換當前檔案 Windows("第" & i & "列開頭" & 副檔名).Activate Range("A1").Select ActiveSheet.Paste '存檔、關閉 ActiveWorkbook.Save ActiveWindow.Close Next MsgBox "Done~ 去剛剛選的資料夾查看成果吧,檔名命名原則為「第X列開頭」" End Sub ``` ### 合併儲存格 > 以A欄B欄為對象 ``` Visual Basic for Applications= Sub 項次加合併() '終點列都是C欄enddown '標項次 Dim c c = 1 ThisWorkbook.Activate For i = 2 To Range("C2").End(xlDown).Row If Range("B" & i) <> "" Then Range("A" & i) = c c = c + 1 End If Next '---- '第一項值合併 Dim n '為了防止最後一列明明不用合併還合併,終點設倒數第二列 For i = 2 To Range("C2").End(xlDown).Row - 1 n = 1 If Range("B" & i) <> "" And Range("B" & i + 1) = "" Then Do Range("B" & i & ":B" & i + n).Select n = n + 1 Debug.Print n If i + n > Range("C2").End(xlDown).Row Then Exit Do Loop Until Range("B" & i + n).Value <> "" End If Selection.Merge Next '------ '項次合併 '為了防止最後一列明明不用合併還合併,終點設倒數第二列 For i = 2 To Range("C2").End(xlDown).Row - 1 n = 1 If Range("A" & i) <> "" And Range("A" & i + 1) = "" Then Do Range("A" & i & ":A" & i + n).Select n = n + 1 Debug.Print n '需要強制結束迴圈 If i + n > Range("C2").End(xlDown).Row Then Exit Do Loop Until Range("A" & i + n).Value <> "" End If Selection.Merge Next End Sub ``` ### 列出所有交叉篩選器 > 若excel有使用交叉篩選器,需定位時可使用 <br> >原來源:https://www.excelcampus.com/vba/vba-macro-list-all-slicers/ ``` Visual Basic for Applications= Sub 列出所有交叉篩選器() 'Description: List all slicers and sheet names in the Immediate window 'Author: Jon Acampora, Excel Campus 'Source: https://www.excelcampus.com/vba/vba-macro-list-all-slicers/ Dim sc As SlicerCache Dim sl As Slicer 'SlicerCache.Name = 程式裡的交叉篩選器名稱 'Slicer.Parent.Name = 交叉篩選器所在表名 For Each sc In ActiveWorkbook.SlicerCaches For Each sl In sc.Slicers For Each si In sc.SlicerItems If si.Selected = True Then Debug.Print sl.Parent.Name & " | " & sl.Name & "|" & si.Name End If 'sl.Caption = slicer header caption 'sl.Parent.Name = worksheet name Next si Next sl Next sc End Sub ``` ### copy上一列 > 相當於整列選取後使用Crlt+D ``` Visual Basic for Applications= Sub copy上一列() Rows("100:100").Select Application.CutCopyMode = False Selection.FillDown End Sub ``` ### 列出所有資料夾 ``` Visual Basic for Applications= Sub 純print() Dim folderPath As String Dim filename, filetype, start_cell, end_col As String Dim wb As Workbook ' '1. 選取檔案所在的資料夾,作為路徑 Set fDialog = Application.FileDialog(msoFileDialogFolderPicker) '2. Optional: Properties fDialog.Title = "請選擇資料夾" '3. 如果有選完資料夾,便生成路徑變數 If fDialog.Show = -1 Then folderPath = fDialog.SelectedItems(1) & "\" End If filename = Dir(folderPath & filetype) Do While filename <> "" Debug.Print filename filename = Dir Loop End Sub ``` > 寫在工作表的版本: ``` Visual Basic for Applications= Sub 寫在格子裡() Dim folderPath As String Dim filename, filetype, n, col Dim wb As Workbook '1. 選取檔案所在的資料夾,作為路徑 Set fDialog = Application.FileDialog(msoFileDialogFolderPicker) '2. Optional: Properties fDialog.Title = "請選擇資料夾" '3. 如果有選完資料夾,便生成路徑變數 If fDialog.Show = -1 Then folderPath = fDialog.SelectedItems(1) & "\" End If filename = Dir(folderPath & filetype) col = InputBox("請選擇放檔名的欄位", "欄位?", "A") If IsEmpty(Range(col & 2)) = True Then n = 2 Else n = Range(col & 2).End(xlDown).Offset(1, 0).Row Do While filename <> "" Range(col & n).Value = filename n = n + 1 filename = Dir Loop End Sub ``` ### 資料reshape ``` Visual Basic for Applications= Sub 一行變成矩陣() '情境:資料全擠在A欄 Dim j, n, st j = 0 n = Range("A1").End(xlDown).Row st = CInt(InputBox("要隔幾筆資料一列?,結果顯示在D2", "隔幾筆", "5")) Debug.Print n 'step: 從第1列到下一列開始貼的列隔多少 'i + (最後要選取的列 - 一開始選取的列) For i = 1 To n Step st Debug.Print i Range(Cells(i, 1), Cells(i + st - 1, 1)).Select Selection.Copy Range("D" & i - (st - 1) * j + 1).Select Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _ False, Transpose:=True j = j + 1 Next End Sub ``` ``` Visual Basic for Applications= Sub 一列變成矩陣() '情境:資料全擠在第一列 Dim j, n, st j = 0 n = Range("A1").End(xlToRight).Column st = CInt(InputBox("要隔幾筆資料一列?,結果顯示在A2", "隔幾筆", "5")) For i = 1 To n Step st Debug.Print 2 + i - (st - 1) * j Range(Cells(1, i), Cells(1, i + st - 1)).Select Selection.Copy Range("A" & 2 + i - (st - 1) * j).Select ActiveSheet.Paste Debug.Print 2 + i - (st - 1) * j j = j + 1 Next End Sub ``` ### 分割資料 > 以等筆數切割資料為數份,並標上欄位名稱 ``` Visual Basic for Applications= Sub 分割資料() Dim 副檔名, FilePath As String Dim 原始檔 As Workbook Dim xDlg As FileDialog Dim filefont, start_col, end_col, diff 副檔名 = "XXX" '設定副檔名,用陽春的if判定filefont要是甚麼屬性(後面會用到) Do Until 副檔名 <> "XXX" 副檔名 = InputBox("檔案要分割成甚麼檔?要輸入副檔名喔喔喔" & vbCrLf _ & "目前可用:xlsx、csv、ods、xls", "求副檔名", "xlsx") If 副檔名 = "csv" Or 副檔名 = ".csv" Then filefont = xlCSV ElseIf 副檔名 = "xlsx" Or 副檔名 = ".xlsx" Then filefont = xlOpenXMLWorkbook ElseIf 副檔名 = "ods" Or 副檔名 = ".ods" Then filefont = xlOpenDocumentSpreadsheet ElseIf 副檔名 = "xls" Or 副檔名 = ".xls" Then filefont = xlExcel8 ElseIf 副檔名 = "" Then '唯一逃出迴圈手段:什麼都不做按取消 End Else MsgBox "這個程式很陽春,不支援這個副檔名><" 副檔名 = "XXX" End If Loop '加點點 If Left(副檔名, 1) <> "." Then 副檔名 = "." & 副檔名 Set xDlg = Application.FileDialog(msoFileDialogFolderPicker) xDlg.Title = "請選擇分割檔案放置的資料夾" '選擇要輸出的資料夾,有選到就存成變數 If xDlg.Show <> -1 Then Exit Sub FilePath = xDlg.SelectedItems(1) & "\" ThisWorkbook.Activate start_col = InputBox("起始欄在?", "起始欄", "A") '調成數字,順便設個取消 If IsNumeric(start_col) = False Then start_col = Range(start_col & 1).Column ElseIf srart_col = "" Then End End If end_col = InputBox("最後一欄在?", "最後一欄", "B") '調成數字,順便設個取消 If IsNumeric(end_col) = False Then end_col = Range(end_col & 1).Column ElseIf end_col = "" Then End End If 'key幾筆資料 diff = InputBox("要幾筆資料為一個檔案?打數字喔", "幾筆", 2000) '變integer(整數)格式 diff = CInt(diff) For i = 2 To ActiveSheet.UsedRange.Rows.Count Step diff ThisWorkbook.Activate '選取位置 Range(Cells(i, start_col), Cells(i + diff - 1, end_col)).Select Selection.Copy Workbooks.Add ActiveSheet.Paste Application.CutCopyMode = False ActiveWorkbook.SaveAs filename:= _ FilePath & "第" & i & "列開頭" & 副檔名, FileFormat:=filefont, _ CreateBackup:=False '插表頭在第一列 Rows("1:1").Select Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove '原檔開啟、複製表頭 ThisWorkbook.Activate Cells(1, start_col).Select Range(Cells(1, start_col), Cells(1, end_col)).Select Selection.Copy '切換當前檔案 Windows("第" & i & "列開頭" & 副檔名).Activate Range("A1").Select ActiveSheet.Paste '存檔、關閉 ActiveWorkbook.Save ActiveWindow.Close Next MsgBox "Done~ 去剛剛選的資料夾查看成果吧,檔名命名原則為「第X列開頭」" End Sub ``` ### 移動檔案 >1.原理<br> >可搭配列出資料夾下所有檔案使用 ``` Visual Basic for Applications= Sub MoveFile() Dim FSO Set FSO = CreateObject("Scripting.FileSystemObject") FSO.MoveFile "C:\Users\Path\d1.docx", _ "C:\Users\Path2\p3\d1.docx" End Sub ``` ### 比對兩張工作表 ``` Visual Basic for Applications= Sub 比對工作表() '假設同一張工作下每列資料都不同 Dim sh1, sh2, sh1_r, sh1_c, sh2_r, sh2_c, str, record '做為比較基準的工作表名稱 sh1 = "工作表1" '欲比較的對象(修改要改它) sh2 = "工作表1 (2)" '總列數(可自定義) sh1_r = Sheets(sh1).Range("A1").End(xlDown).Row sh2_r = Sheets(sh2).Range("A1").End(xlDown).Row '總行數(可自定義) sh1_c = Sheets(sh1).Range("A1").End(xlToRight).Column sh2_c = Sheets(sh1).Range("A1").End(xlToRight).Column '製作字典 Dim dict As Object Set dict = CreateObject("Scripting.Dictionary") For i = 2 To sh1_r str = "" For j = 1 To sh1_c str = str & Cells(i, j).Value Next j dict.Add str, i Next i For i = 2 To sh2_r str = "" For j = 1 To sh2_c str = str & Cells(i, j).Value Next j If dict.Exists(str) Then record = i & "、" Next i If Right(record, 1) = "、" Then record = Left(record, Len(record) - 1) Debug.Print "第" & record & "列資料" & sh_1 & "沒有" End Sub ```