初めに
今回の記事はVBA勉強会にて、お題に沿って自分なりにVBAを書いたものになります。
私自身VBA歴はまだまだ浅く、勉強中の身ですのでベストプラクティスとは言えないコードになっていることと思います。そのためあまり参考にならない可能性がありますのでご了承ください。
お題の内容
「社員情報の更新」
社員情報をエクセルで管理し、新入社員や中途社員といった新規社員の追加や、所属支店、氏名の変更が発生したケースについてです。
手動での変更はミスの温床となってしまいます。
そこで、VBAを使用して自動での情報更新を行なってみましょう!
今回も、記述方法、トリガー条件は自由です。
配布ファイルは
「旧社員マスタ」
「変更社員情報」
の2つです。
「変更社員情報」には変更のある社員情報が記載されています。これを元に「旧社員マスタ」の情報を更新してください。
「変更社員情報」は全ての項目が変更されているわけではありません。所属のみ変更されている場合や、氏名のみの変更もあります。
ファイルの内容
コードと実行結果
Option Explicit
Sub 実行()
Application.ScreenUpdating = False
Dim FilePath As String: FilePath = ThisWorkbook.Path
Workbooks.Open FilePath & "\" & "変更社員情報.xlsx", ReadOnly:=True
Dim wb As Workbook: Set wb = ActiveWorkbook
Dim ws As Worksheet: Set ws = wb.Sheets("社員マスタ")
Dim i, j As Long '※←ミスコード! i がVariant型になる。
Dim target As Range '検索で使用
Dim Arr As Variant: Arr = ws.Range("A1").CurrentRegion '更新データを配列に格納
wb.Close
'新しいデータの数だけ繰り返し
For i = 2 To UBound(Arr, 1)
Set target = Cells.Find(what:=Arr(i, 1)) '変更する社員IDをターゲットに格納
If target Is Nothing Then '変更するセルが見つからなかったら、最終行をターゲットにセット
Set target = Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
End If
'更新する列の数だけ繰り返し
For j = 1 To UBound(Arr, 2)
target.Offset(0, j - 1) = Arr(i, j)
Next
Next
'罫線を引く
Range("A1").CurrentRegion.Borders.LineStyle = xlContinuous
Application.ScreenUpdating = True
End Sub
Findメソッドで社員番号が見つかった場合
Set target = Cells.Find(what:=Arr(i, 1)) '変更する社員IDをターゲットに格納
見つかった場合、見つかった場所を起点に転記処理を行っていきます。
(変更点以外の転記は無駄ですが、いったんそのままスルーしてください)
'更新する列の数だけ繰り返し
For j = 1 To UBound(Arr, 2)
target.Offset(0, j - 1) = Arr(i, j)
Next
見つからなかった場合
検索して見つからなかった場合(RangeオブジェクトのtargetがNothingだったら)
下記のコードで、1列目の最終行から一つ下の行をターゲットとして処理を行っていきます。
先ほど変更点以外上書きしても無駄だといいましたが、こうすることで追加の場合と上書きの場合で処理を共通化できて、コードがすっきりするかなと思った次第です。
'見つからない場合、最終行をターゲットにセット
If target Is Nothing Then
Set target = Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
End If
'更新する列の数だけ繰り返し
For j = 1 To UBound(Arr, 2)
target.Offset(0, j - 1) = Arr(i, j)
Next
実行結果
変更情報の値に更新され、項目も追加されていることがわかるかと思います。
感想
今回、とにかくコードが短くできないかなと考えて、更新情報の上書きと追加の処理を共通化してみたという感じです。(成果の発表の際長い間しゃべりたくないので、できるだけコードを短くして説明をできるだけ短くしたいという魂胆w)
今回学びもあり実りのある勉強会だったと思います。
あと初めてgif作ってみたけど楽しい。。。(笑)
学んだこと
変数はまとめて宣言できる認識だったが、今回型を明示的に指定しておらず想定とは違う型になっていた。※勉強会にてご指摘いただきました。
Dim i, j As Long '※←ミスコード! i がVariant型になる。
Arrの宣言時、Arr()としていないのでRangeオブジェクトが配列に格納されており、そのため配列のインデックス番号が1から始まっていた。配列は配列でも格納する情報が異なると、0から始まらないこともあるということが分かった。
Dim Arr As Variant: Arr = ws.Range("A1").CurrentRegion '更新データを配列に格納
if文の省略形があることを知ることができた。
分岐しない場合は、一行に収めることで、End If を省略できるらしい。ビビりまくった。
If target Is Nothing Then
Set target = Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
End If
If target Is Nothing Then Set target = Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
以上です。