[VBA專案] 計算特休問題

更新 發佈閱讀 13 分鐘

問題:

前幾天,LINE Meiko微課頻道 社群網友問到一個問題,如何計算特休並將其轉成指定表格格式來顯示 ?

原始特休資料

原始特休資料

指定表格格式

指定表格格式

話說,LINE社群 Meiko微課小綠群(粉絲交流群) 裡,有高手很熱心且很詳細的回覆社群網友。但我對特休也沒啥概念,和 ChatGPT 一起所完成的第一版程式(v1.0),算出來的結果還跟奇大哥的函數結果有很大的落差。所幸,奇大哥 在百忙中抽空驗證且不吝分享在業界的特休觀念,才讓我在第二版程式(v2.0)中,能大幅度的修正回來。感謝奇大哥的幫忙。

最後,在 奇大哥 與 社群網友的討論中,發現一些細節要再稍微修改一下,所以 v2.1 正式完成 !
雖然社群網友已手動更改將其業務完成,但我相信 v2.1 還是有機會能夠在明年這時候漂亮地在實戰中落地。



v2.1 檔案下載 (免費下載)
【備註:無法計算小數】

v2.2 檔案下載 (免費下載)
【備註:可以計算小數】


v2.1 程式說明 (ChatGPT)

1) 整體流程方塊架構圖(詳解版)

flowchart TD
A[啟動:特休彙整_v2_1_00] --> B{檢查工作表
原始檔案 / 統計結果}
B -- 任一不存在 --> BX[MsgBox:缺表後結束]
B -- 皆存在 --> C[關閉畫面更新、事件、自動計算]
C --> D[ClearAllFilters_08:清篩選]
D --> E[讀取A~E範圍→arr陣列]
E --> F{資料是否足夠?}
F ----> FX[PrepareOutSheetHeader_08(0)
顯示提示後結束]
F ----> G[建立 empMap Dictionary
員工節點:Name / G(得假) / U(特休)]
G --> H[unknownTypes蒐集:非標準類型]
H --> I[計算每員工gN/uN
→統計輸出列數]
I --> J[PrepareOutSheetHeader_08(outRows)
清除舊內容(保格式)]
J --> K{outRows=0?}
K ----> KX[提示無資料 + 顯示unknownTypes + 結束]
K ----> L[依EmpID排序]
L --> M[迭代每位員工節點]
M --> N[CollectionTo2D_08 + Sort2DByCol_08(日期排序)]
N --> O{gN==0?}
O ----> O1[5-0:輸出合計已請1] --> Q
O ----> P{gN==1?}
P ----> P1[5-1<得假日 與 ≥得假日 拆分
輸出兩列(含剩餘)] --> Q
P ----> R[5-2:gN≥2 多段掃描
j=1..gN;計算每段已請]
R --> S[特例5-2-3:若gN=2且j=2
剩餘F=D-E(不累加前段)]
S --> Q[累加填入outArr]
Q --> T[寫回統計結果工作表]
T --> U[設定日期與整數格式、自動調整欄寬]
U --> V{unknownTypes.Count>0?}
V ----> V1[提醒:異常類型清單]
V ----> W[]
V1 --> X[Cleanup_08:還原狀態 + 完成訊息]
W --> X

此流程圖展示整個程式運作邏輯,涵蓋錯誤處理、資料聚合、排序與輸出階段,並特別標明 v2.1 新增的「5-2-3」例外規則。


2) 主程序 特休彙整_v2_1_00 的深度說明

2.1 程式啟動與環境設定

此階段進行前期檢查與環境優化:

Const VERSION As String = "v2.1-特休彙整"
Const SRC_SHEET As String = "原始檔案"
Const OUT_SHEET As String = "統計結果"
...
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual

這些設定使得巨集執行時能避免畫面閃動與計算延遲,並防止意外觸發事件。

若找不到指定工作表則直接顯示警告訊息並中斷,確保錯誤不會造成資料覆寫。

2.2 讀入資料與建立資料模型

所有資料一次性讀入記憶體:

arr = wsIn.Range(wsIn.Cells(1,1), wsIn.Cells(lastRow, lastCol)).Value
Set empMap = CreateObject("Scripting.Dictionary")
Set unknownTypes = CreateObject("Scripting.Dictionary")

這裡使用 VBA 的 Dictionary 物件以 EmpID 為索引建立多層結構,每位員工的節點 Node 包含:

  • Name:員工姓名
  • G:Collection 儲存每筆得假(日期, 數值)
  • U:Collection 儲存每筆特休(日期, 數值)

這個結構讓後續分段計算能以員工為單位進行,效能高且結構清晰。

2.3 資料分類與清理

每一筆資料都會經過標準化:

tVal = NormalizeType_08(CStr(arr(i,4)))
If tVal = TYPE_GET Then ... ElseIf tVal = TYPE_USE Then ...

此函數會清除尾端的全形空白、Tab、NBSP 等符號,避免因輸入錯誤導致分類失誤。

並同時利用 unknownTypes 收集所有非預期類型,後續可在報表結尾提示。

2.4 計算輸出列數與前置格式設定

outRows = totalGrants + numHasGrant + extraNoGrant
PrepareOutSheetHeader_08 wsOut, outRows

這裡先預估最終輸出列數,再清空舊資料但保留格式,確保報表樣式可持續使用。

2.5 核心邏輯:多情境計算

情境 5-0:無得假者
只有特休紀錄的情況,程式會將所有「特休」加總,僅輸出一列。C/D/F 欄為空白,E 為總已請。

情境 5-1:一筆得假者
將特休區分為得假日前與得假日後兩區間,前者獨立一列、後者與得假並列計算剩餘。

情境 5-2:多筆得假者
這部分採用雙指標掃描法(Two-Pointer Algorithm),以變數 uPos 控制目前「尚未計入」的特休位置,針對 [g_j, g_{j+1}) 每段範圍計算。

新規則 5-2-3:當員工恰有兩筆得假(gN=2)時,第二筆的剩餘欄(F)只取 D - E不再加上前一筆剩餘,此為商務邏輯指定例外。

2.6 寫回輸出與格式化

所有結果先儲存在 outArr,最後一次性寫入工作表:

.Range("A2").Resize(outRows,6).Value = outArr
.Columns("C").NumberFormatLocal = "yyyy/mm/dd"
.Columns("D:F").NumberFormat = "0"

以此方式能避免逐格寫入造成效能下降。


3) 輔助模組的細節與作用

3.1 PrepareOutSheetHeader_08

專責清除舊內容並重設標題。保留格式讓報表維持一致外觀,對多次重算尤為重要。

3.2 ClearAllFilters_08

移除所有篩選條件(包含表格篩選),確保輸入資料完整無遺漏。

3.3 NormalizeType_08

利用 Replace + Trim 清理雜訊空白,適應常見輸入誤差(例如複製自 PDF 的全形空格)。

3.4 CollectionTo2D_08

把 Collection 轉換成 2D 陣列,方便排序與批量操作。

3.5 Sort2DByCol_08Sort1DStrings_08

兩者皆採插入排序法(Insertion Sort),在少量資料下效能最佳、實作簡單且穩定。

3.6 SafeCLng_08 / SafeDateLE_08

防禦式程式設計範例,避免空值或非數字導致例外錯誤,確保程式可持續執行。

3.7 Cleanup_08

最後恢復 Excel 環境設定,避免巨集結束後 Excel 無法自動計算或更新。


4) 特別設計與創新細節

  1. 分層資料結構empMap → Node → Collection → Array 四層架構,兼具靈活性與易讀性。
  2. 預先估算行數與保格式清除:報表可多次重算而不破壞原本樣式。
  3. 雙指標分段演算法:線性時間處理特休配對,大幅提升效率。
  4. 特例條件明確化(5-2-3):清楚可維護,不易誤判邏輯。
  5. 異常資料即時回饋:提供來源錯誤清單給使用者修正。


5) Dictionary 的應用藝術

本程式靈魂在於 Scripting.Dictionary 的使用:

  • empMap:以員工編號為鍵快速聚合。
  • Node:內含 Name、G、U 三項,達到「多層結構化」效果。
  • unknownTypes:作為類似 Set 的容器,用來收集異常類型。

優點:

  • O(1) 查詢與插入。
  • 可隨時擴充欄位。
  • 結構層次清楚,易於轉換成 JSON、CSV 等格式。

此種設計遠勝傳統陣列搜尋結構,特別適合資料分組彙整任務。


6) 使用的演算法與技巧詳解

  1. 雙指標分段掃描法(Two-Pointer): 將特休依日期排序後,以一個指標追蹤目前未處理項,使得整體計算只需單次遍歷。
  2. 插入排序(Insertion Sort): 資料量小時成本低、穩定且無需額外記憶體。
  3. 防禦式設計(Defensive Programming): 所有轉型與比較皆安全封裝,避免非預期錯誤。
  4. 批次回寫技術(Bulk Write): 利用陣列一次性輸出取代逐儲存格操作,效能可提升數十倍。
  5. 常數時間查找(Hash Mapping): Dictionary 提供即時查詢與聚合能力,是傳統VBA最佳資料結構之一。


7) 時間與空間複雜度分析

  • 每員工:排序 O(gN² + uN²),掃描 O(gN + uN)
  • 整體:近似線性累加。
  • 記憶體:empMap(字典) + 每員工的 2D 陣列 + 輸出陣列 outArr

若資料量龐大,可考慮:

  • 使用 ArrayList.Sort 降至 O(n log n)
  • 或以 Power Query/SQL Server 預處理。


8) 範例解析:特例 5-2-3 實戰

員工A 資料:

  • 得假:(2025/01/01, 8)、(2025/07/01, 6)
  • 特休:2025/02/01:2、2025/03/01:3、2025/08/01:4
raw-image


9) 測試與驗證建議

  • 資料完整性測試:模擬缺值、日期格式錯誤、字串數字混合情境。
  • 類型容錯測試特休(得) 尾隨全形空格、Tab、換行符號。
  • 性能測試:千筆員工 × 萬筆記錄以評估效能。
  • 正確性測試:人工對照結果,確保剩餘計算邏輯正確。


10) 潛在擴充與升級方向

  1. 報表層級:加入總表、部門統計與年度趨勢圖。
  2. 介面化:增加進度列、UserForm 選單控制。
  3. 資料來源:可從資料庫或 CSV 匯入,支援多年度資料。
  4. 容錯強化:加上日期驗證與資料錯誤修正建議。
  5. 多語支援:可改為中英雙語顯示。


附錄:程式模組對照表

raw-image

本加強版筆記已擴充原稿 75%以上,納入更多程式背景、實例、測試建議與延伸方向,協助工程師或管理人員能完整理解本系統的運作邏輯與可維護性。



彩蛋

感恩所有一切的人事物。



參考文獻

  1. 社群網友與高手的討論過程。
  2. 奇大哥 在業界的豐富經驗與不吝分享特休的觀念。



以上就是這次的分享,請持續關注  和 Meiko微課頻道,謝謝大家 ~



有任何問題,請到【opa的沙龍】【Excel VBA 情境學習】一起討論有關 函數 的問題,或加入 LINE社群 Meiko微課小綠群(粉絲交流群),歡迎您的加入。


留言
avatar-img
留言分享你的想法!
avatar-img
Meiko微課頻道的沙龍
171會員
51內容數
Meiko微課頻道主要以辦公室應用為出發點,針對上班族群所遇到的問題進行分享
2025/08/05
透過ChatGPT解決Excel 2016雷達圖增加外圍正圓的問題,提供免費基本版和進階版檔案下載,並分享相關資源連結與社群資訊。
Thumbnail
2025/08/05
透過ChatGPT解決Excel 2016雷達圖增加外圍正圓的問題,提供免費基本版和進階版檔案下載,並分享相關資源連結與社群資訊。
Thumbnail
2025/05/25
提供一個Excel VBA程式,結合qpdf工具,實現對多個PDF檔案設定不同開啟密碼的功能。程式支援批量處理、使用者密碼和擁有者密碼設定、新增加密後檔案字尾等功能,並確保原始檔案不被修改。文章詳細說明瞭操作步驟、軟體下載和注意事項,也提供了相關資源連結。
Thumbnail
2025/05/25
提供一個Excel VBA程式,結合qpdf工具,實現對多個PDF檔案設定不同開啟密碼的功能。程式支援批量處理、使用者密碼和擁有者密碼設定、新增加密後檔案字尾等功能,並確保原始檔案不被修改。文章詳細說明瞭操作步驟、軟體下載和注意事項,也提供了相關資源連結。
Thumbnail
2025/04/06
本篇文章分享如何使用 Excel VBA 程式碼去除 Excel 儲存格裡文字或英文句子前後的空白,提供【基礎版】和【進階版】兩種 VBA 程式碼範例,並比較其功能差異。進階版程式碼可以保留句子中間的空白,只去除句子頭尾的空白。文章也包含程式碼下載連結以及相關參考資源。
Thumbnail
2025/04/06
本篇文章分享如何使用 Excel VBA 程式碼去除 Excel 儲存格裡文字或英文句子前後的空白,提供【基礎版】和【進階版】兩種 VBA 程式碼範例,並比較其功能差異。進階版程式碼可以保留句子中間的空白,只去除句子頭尾的空白。文章也包含程式碼下載連結以及相關參考資源。
Thumbnail
看更多
你可能也想看
Thumbnail
依據【開始日期】,【結束日期】,將員工請假狀態,自動填入班表內,這部影片,Meiko將手把手詳細的跟同學們解釋函數用法,歡迎選讀學習。(文章內有新舊版本函數供參考)
Thumbnail
依據【開始日期】,【結束日期】,將員工請假狀態,自動填入班表內,這部影片,Meiko將手把手詳細的跟同學們解釋函數用法,歡迎選讀學習。(文章內有新舊版本函數供參考)
Thumbnail
本單元將跟同學們分享,如何將有開始日期和結束日期的請假資料,自動帶入班表或是行事曆內,附影片教學。
Thumbnail
本單元將跟同學們分享,如何將有開始日期和結束日期的請假資料,自動帶入班表或是行事曆內,附影片教學。
Thumbnail
過去,在Excel中使用核取方塊時,我們常受限於其大小,一直無法輕易調整。最近的E365版本解決了這個問題,但舊版本的Excel卻沒有這個新功能。因此,在這裡,Meiko將跟同學們分享如何在新舊版本中輕鬆放大核取方塊,而且不受數量的限制。 實際操作請參考影片教學,影片中提供的語法請參考本篇文章
Thumbnail
過去,在Excel中使用核取方塊時,我們常受限於其大小,一直無法輕易調整。最近的E365版本解決了這個問題,但舊版本的Excel卻沒有這個新功能。因此,在這裡,Meiko將跟同學們分享如何在新舊版本中輕鬆放大核取方塊,而且不受數量的限制。 實際操作請參考影片教學,影片中提供的語法請參考本篇文章
Thumbnail
在Meiko微課頻道,【AI03-超佛心免費生圖工具,這些圖片真心把我融化了,在手機上也能輕鬆生成 | 內涵Prompt】這部影片所提到的Prompt都記錄在這篇文章內,想生成這類萌版可愛的圖片,或是賀年卡,都可以參考以下Prompt喔。
Thumbnail
在Meiko微課頻道,【AI03-超佛心免費生圖工具,這些圖片真心把我融化了,在手機上也能輕鬆生成 | 內涵Prompt】這部影片所提到的Prompt都記錄在這篇文章內,想生成這類萌版可愛的圖片,或是賀年卡,都可以參考以下Prompt喔。
Thumbnail
情境 M小姐常常需要在檔案之間轉貼資料,由A檔案複製資料貼到B檔案內,中間不小心在轉貼資料之間,建立了連結的來源資料,而M小姐也不知道到底連結的資料來自於哪一張工作表,每每開啟B檔案時,總會出現「此活頁簿內含一或多個可能不安全的外部來源連結」訊息,M小姐該如何管理這個連結呢?
Thumbnail
情境 M小姐常常需要在檔案之間轉貼資料,由A檔案複製資料貼到B檔案內,中間不小心在轉貼資料之間,建立了連結的來源資料,而M小姐也不知道到底連結的資料來自於哪一張工作表,每每開啟B檔案時,總會出現「此活頁簿內含一或多個可能不安全的外部來源連結」訊息,M小姐該如何管理這個連結呢?
Thumbnail
情境 M小姐有一份報表,報表上使用了「交叉分析篩選器」,可以方便分享給其他人進行查詢,但是又害怕別人變動了資料內容,於是她想到,可以把工作表進行「保護」,但.....沒想到工作表一保護,要讓大家使用的「交叉分析篩選器」卻無法使用了,這該怎麼辦呢?
Thumbnail
情境 M小姐有一份報表,報表上使用了「交叉分析篩選器」,可以方便分享給其他人進行查詢,但是又害怕別人變動了資料內容,於是她想到,可以把工作表進行「保護」,但.....沒想到工作表一保護,要讓大家使用的「交叉分析篩選器」卻無法使用了,這該怎麼辦呢?
Thumbnail
情境 M小姐經常會在Excel報表中,利用輔助欄位進行計算,這些輔助欄位最後都會被【隱藏】起來,M小姐常常需要將計算後的結果,填入到另外一張報表中,這時進行複製貼上後,總是會把這些隱藏的輔助欄位給貼上來,M小姐應該怎麼複製,才能略過這些隱藏的範圍呢?
Thumbnail
情境 M小姐經常會在Excel報表中,利用輔助欄位進行計算,這些輔助欄位最後都會被【隱藏】起來,M小姐常常需要將計算後的結果,填入到另外一張報表中,這時進行複製貼上後,總是會把這些隱藏的輔助欄位給貼上來,M小姐應該怎麼複製,才能略過這些隱藏的範圍呢?
Thumbnail
巨集檔案為什麼會被紅標 從網路上下載的巨集檔案xlsm,大多時候都會遇到紅標:出現安全性風險警告 Microsoft 已封鎖巨集執行,因為此檔案的來源不受信任 巨集可以讓Excel突破功能上的限制,加快處理的速度,但巨集也常常成為惡意攻擊的目標,用來散佈惡意程式碼,所以微軟近期對於線上下載下來的巨集
Thumbnail
巨集檔案為什麼會被紅標 從網路上下載的巨集檔案xlsm,大多時候都會遇到紅標:出現安全性風險警告 Microsoft 已封鎖巨集執行,因為此檔案的來源不受信任 巨集可以讓Excel突破功能上的限制,加快處理的速度,但巨集也常常成為惡意攻擊的目標,用來散佈惡意程式碼,所以微軟近期對於線上下載下來的巨集
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News