「窓口担当」「電話当番」「雑務担当」など、
毎日担当を決めるのって、地味に大変ですよね。
人が増えると、偏りなくローテーションさせることも難しくなります。
そこで今回は、ExcelVBAで担当者を自動割り振りする勤務表マクロを紹介します。
今回のマクロはこんなイメージです。
- 「担当者一覧」シートにメンバーを登録
- 「勤務表」シートに日付と担当区分(窓口・電話・雑務など)を用意
- ボタン1つで、担当者が順番にローテーションして自動で割り振られる

この記事で作るもの
今回は、次のようなシンプルな勤務表を例にします。
① 担当者一覧シート(シート名:担当者一覧)

② 勤務表シート(シート名:勤務表)

この状態でマクロを実行すると、
メンバーがぐるぐると順番にローテーションして担当が自動で埋まるようにします。
マクロの全体像(コピペOK)
以下のコードを標準モジュールに貼り付けるだけで動きます。
Option Explicit
' 勤務表に担当者を自動割り振りするマクロ
Sub AssignDuty()
Dim wsMember As Worksheet ' 担当者一覧シート
Dim wsDuty As Worksheet ' 勤務表シート
Dim lastMemberRow As Long
Dim lastDutyRow As Long
Dim members() As String ' 担当者名を入れる配列
Dim memberCount As Long
Dim i As Long, r As Long, c As Long
Dim idx As Long ' ローテーション用インデックス
' シートをセット
Set wsMember = Worksheets("担当者一覧")
Set wsDuty = Worksheets("勤務表")
' 担当者一覧の最終行を取得(A列)
lastMemberRow = wsMember.Cells(wsMember.Rows.Count, "A").End(xlUp).Row
memberCount = lastMemberRow - 1 ' 1行目は見出し想定なら -1、見出しなしならそのまま
If memberCount <= 0 Then
MsgBox "担当者一覧シートに担当者が登録されていません。", vbExclamation
Exit Sub
End If
' 担当者配列を作成(2行目から下を読み込む想定)
ReDim members(1 To memberCount)
For i = 1 To memberCount
members(i) = wsMember.Cells(i + 1, "A").Value
Next i
' 勤務表の日付行数を取得(A列)
lastDutyRow = wsDuty.Cells(wsDuty.Rows.Count, "A").End(xlUp).Row
If lastDutyRow <= 1 Then
MsgBox "勤務表シートのA列に日付が入力されていません。", vbExclamation
Exit Sub
End If
' 既存の担当者列(B列以降)をクリア
wsDuty.Range(wsDuty.Cells(2, 2), wsDuty.Cells(lastDutyRow, wsDuty.Cells(1, wsDuty.Columns.Count).End(xlToLeft).Column)).ClearContents
' ローテーション開始位置
idx = 1
' 行(=日付)ごとに、列(=担当区分)を埋めていく
For r = 2 To lastDutyRow ' 2行目から最終行まで
' 1行目の最終列(=担当区分の右端)を取得
Dim lastCol As Long
lastCol = wsDuty.Cells(1, wsDuty.Columns.Count).End(xlToLeft).Column
For c = 2 To lastCol ' B列(2) から 最終列 まで
wsDuty.Cells(r, c).Value = members(idx)
' 次の担当者にインデックスを進める(末尾まで行ったら先頭に戻る)
idx = idx + 1
If idx > memberCount Then
idx = 1
End If
Next c
Next r
MsgBox "勤務表の担当者割り振りが完了しました。", vbInformation
End Sub
コードのポイント解説(初心者向け)
① 担当者を配列に入れておく
ReDim members(1 To memberCount)
For i = 1 To memberCount
members(i) = wsMember.Cells(i + 1, "A").Value
Next i
「担当者一覧」シートの A 列から、担当者名を配列に読み込みます。
配列にしておくことで、ぐるぐる順番に割り当てる処理が簡単になります。
② 勤務表の日数と列数を自動で判定
lastDutyRow = wsDuty.Cells(wsDuty.Rows.Count, "A").End(xlUp).Row
lastCol = wsDuty.Cells(1, wsDuty.Columns.Count).End(xlToLeft).Column
– A列 … 日付が入っている行の最後までを勤務対象 – 1行目 … B列以降に「窓口」「電話」「雑務」などの担当区分が入っている想定
そのため、列数を増やしても減らしても、マクロ側は自動で対応できます。
③ ローテーション(ぐるぐる回す)処理
wsDuty.Cells(r, c).Value = members(idx)
idx = idx + 1
If idx > memberCount Then
idx = 1
End If
ここが一番大事な部分です。
担当者配列 members() のインデックス idx を1つずつ進め、最後まで行ったら1に戻すことで、
担当者を公平にローテーションしていく仕組みを実現しています。
④ 既存の担当割り振りは一旦クリア
wsDuty.Range(wsDuty.Cells(2, 2), wsDuty.Cells(lastDutyRow, lastCol)).ClearContents
何度もマクロを実行しても問題ないように、 まずは担当者欄(B列〜最終列、2行目〜最終行)を一度クリアしてから割り当て直しています。
応用テクニック:もう一歩実務寄りにするなら
① 土日を飛ばしたい(平日だけ担当者を割り当てたい)
A列に日付が入っている前提で、For r = 2 To lastDutyRow のループ内に「曜日判定」を入れると、土日をスキップできます。
Dim d As Date
d = wsDuty.Cells(r, 1).Value
If Weekday(d, vbMonday) > 5 Then
' 土日なら飛ばす(6=土, 7=日)
GoTo NextRow
End If
' …ここに担当割り振り処理…
NextRow:
Next r
② 特定の担当は「この人だけ」にしたい
例えば、「電話」は必ず新人以外にしたい…などの制約がある場合は、
列ごとに担当候補リストを変える方法もあります。
- C列(電話)用の配列
phoneMembers() - B列(窓口)用の配列
windowMembers()
といった形で、列ごとにローテーション対象を変えることもできます。
③ 担当回数をカウントして「より少ない人」を優先
今回のマクロは「ぐるぐる順番に回す」方式でしたが、
「担当回数が少ない人を優先する」という方式に変えることもできます。
その場合は、勤務表の下部などに「担当回数」を集計しておき、 VBAでそれを参照しながら担当を決めるようにします。
マクロの設置と実行手順
- 「担当者一覧」シートと「勤務表」シートを作成する
- 担当者一覧シートのA列にメンバー名を入力する(2行目から下)
- 勤務表シートのA列に日付、1行目のB列以降に「窓口」「電話」などの見出しを入力する
- Alt + F11 でVBEを開き、「挿入」→「標準モジュール」を選択
- 今回の
AssignDutyマクロを貼り付ける - Excelに戻り、「開発」タブ →「マクロ」→
AssignDutyを実行
これで、勤務表に担当者が自動で割り振られます。
まとめ:担当者の公平なローテーションはVBAで一発
今回は、担当者を自動割り振りする勤務表マクロをご紹介しました。
- 担当者一覧シートからメンバーを配列に読み込む
- 勤務表の行(=日付)×列(=担当区分)を一気に埋める
- 配列のインデックスをぐるぐる回すことで公平にローテーション
- 土日スキップ・担当ごとの候補制限など、実務に合わせて応用可能
毎月・毎週の担当決めは、意外と時間と気を遣う作業です。
一度マクロを作ってしまえば、ボタン一つで何度でもやり直しができるので、
ぜひご自身の勤務表に合わせてカスタマイズしてみてください。
「この条件も加えたい」「三交代制に対応したい」などのご要望があれば、
応用編として別記事で取り上げることもできますので、ぜひコメントなどで教えてください。


コメント