功能概述:
用指定列來記錄對應行數據是否有更新,如果更新(增刪改),則將當前日期記錄到對應單元格中。
一、運行前准備
運行前准備二選一,由於Excel2007版本以上,基於安全考慮微軟將Excel數據文件與腳本文件分離,數據文件xlsx,腳本文件xlsm。但是2003以下版本數據文件和腳本文件是可以同時保存的。
所以如果是2007以上版本,要么另存后xlsm后添加運行腳本;要么另存為xls后添加運行腳本。
以下是兩種方案
1、基於2007以上版本 -xlsx
1)修改“保存時從文件屬性中刪除個人信息(R)”,取消√
設置調整后保存vba腳本才不會報錯
2)Excel文件另存為.xlsm文件,因為從2003版本以后為了安全,Excel文件跟腳本文件分開。
在.xlsx下保存vba腳本時報錯信息
2、基於2003以下版本-xls
將文件另存為2003以下版本.xls
二、添加腳本代碼
1、鼠標右鍵單擊工作表——“查看代碼” 或通過快捷鍵“Alt+F11”
2、將代碼粘貼進去,並保存關閉即可。
三、代碼內容1-基於工作表Worksheet
'功能概述:用指定列來記錄對應行數據是否有更新,如果更新(增刪改),則將當前日期記錄到對應單元格中。 '實現邏輯 '1.通過Worksheet_SelectionChange事件獲取修改前的值 '2.通過變量tagCol設置要記錄修改記錄的列 '3.循環判斷修改后的單元格所在的行(除用來記錄修改記錄的單元格tagCol外)是非空nulFlag=True並直接退出循環 '4.判斷修改的列為非tagCol列,且該行有記錄非空nulFlag=True,且修改前和修改后的值不相等,則將tagCol的值修改為當前日期date() '5.如果tagCol為空nulFlag=False,則清空tagCol Option Explicit Dim oldValue Private Sub Worksheet_SelectionChange(ByVal Target As Range) '用此事件獲取修改前的值 oldValue = Target.Value End Sub Private Sub Worksheet_Change(ByVal Target As Range) 'On Error Resume Next '跳過異常 On Error GoTo MyErr '用此事件獲取修改后的值 Dim row '事件所在的行 Dim tagCol, col '記錄時間的列 Dim nulFlag '對應行數據單元格是否非空 Dim i row = Target.row col = Target.Column tagCol = 8 ' 第8列 "H",即 nulFlag = False '用來判斷光標所在的行是否為非空,非空為True,空為False '啟用事件 'Application.EnableEvents = True '判斷從該行從1-8內容是否非空 For i = 1 To tagCol - 1 '最后一列除外 If Application.WorksheetFunction.CountA(Cells(row, i)) <> 0 Then nulFlag = True Exit For '如果判斷目標行有非空單元格,則退出循環 End If Next '非tagCol值發生變化,更新tagCol列 If col <> tagCol And nulFlag = True And oldValue <> Target.Value Then Cells(row, tagCol) = Date End If If nulFlag = False Then Cells(row, tagCol) = "" End If '禁用事件 'Application.EnableEvents = False MyErr: 'MsgBox " 錯誤 " & Err.Number & " : " & Err.Description Resume Next End Sub
四、代碼邏輯2-基於工作簿Workbook
基於“三、代碼內容1-基於工作表Worksheet” 的代碼邏輯存在性能和邏輯上的瓶頸,說明如下:
1、以上基於工作表Worksheet的事件,每個工作表都要copy一份代碼,而基於工作簿Workbook的事件只需要一份代碼即可。
2、以上判斷整列是否為空,為空則不處理需要循環逐條判斷,判斷次數較多,效率低;本次直接對整行使用CountA函數,僅進行一次判斷,統計為0則退出事件
3、怎么使用?打開VBE(方式之一:鼠標右鍵單擊工作表名稱,例如Shee1——查看代碼——將代碼復制到ThisWorkbook中),如圖:
4、代碼邏輯如下:
Dim oldvalue '全局變量,用來記錄單元格修改前的值 Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range) '記錄單元格修改前的值 oldvalue = Target.Value End Sub Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) On Error Resume Next '跳過異常 Application.ScreenUpdating = False '關閉屏幕更新
'排除特定工作表,如果工作表名稱時如下名稱,則退出事件 If Sh.Name = "轉置" Or Sh.Name = "工資條" Or Sh.Name = "商品名稱" Then Exit Sub End If Dim tagCol tagCol = 8 '“修改日期”字段所在工作表的列數,此表為第8列,用邏輯來識別該參數邏輯較為復雜(效率比較低),直接寫死即可 '判斷第1列到“修改日期”列中是否有值,沒有值則退出事件 If Application.WorksheetFunction.CountA(Range(Cells(Target.row, 1), Cells(Target.row, tagCol))) = 0 Then Exit Sub End If '如果同時選擇操作多個單元格,僅處理選中區域內的第一個單元格 If Target.Column > 1 Then Set Target = Target.Cells(1) End If '判斷新舊值不相等,且修改的單元格的列要在“修改日期”的列之前(不包含) If Target.Value <> oldvalue And Target.Column < tagCol Then Cells(Target.row, tagCol) = Date End If
Application.ScreenUpdating = True '恢復屏幕更新 End Sub
五、測試
修改其中一個值,觀察“修改日期”單元格內容是否變化