• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:VBAに関する質問です)

VBA初心者の労務管理者向けの質問

このQ&Aのポイント
  • VBAの超初心者が、労務管理で悩んでいます。労務データの管理や計算を自動化するためのVBAマクロを作りたいと考えています。
  • 質問の内容は、社員の休業や休暇の種類と日数を管理するExcelシートのデータを基に、各コードごとの休業日数を算出する方法についてです。
  • 現在の実装では、コード10の休暇日数を算出することができていますが、コード11と12についても同じように日数を算出したいと考えています。

質問者が選んだベストアンサー

  • ベストアンサー
  • jcctaira
  • ベストアンサー率58% (119/204)
回答No.1

mont___blancさん こんにちは。   最初の表と2番目の表の違いや意味が理解できていませんが、 とりあえずプログラムをシンプル(処理スピードを考えない等)に作成しました。   Sub 休業日数計算()  Dim I  As Long  Dim J  As Long  Dim K  As Long  Range("G2:I6000").ClearContents  For I = 2 To 6000   For J = 1 To 5 Step 2    For K = 7 To 9     If Cells(I, J) = Cells(1, K) Then      Cells(I, K) = Cells(I, K) + Cells(I, J + 1)      Exit For     End If    Next K   Next J  Next I End Sub

mont___blanc
質問者

お礼

ありがとうございます!本日出社して早々にこの記述で試してみました。たしかに時間は掛かりましたが、求めていた回答が得られ助かりました。 感謝です。

その他の回答 (2)

  • MAXIMAX
  • ベストアンサー率60% (50/83)
回答No.3

なかなか頑張らられいるようで、応援したいところです^^。コード的な回答は出てきているようなので、最終的にもどうしてもこの表の形式でやりたいという前提は取っ払って、SE 視点での回答(レクチャー?)です。求められている答えとは違うかと思いますが、今後の参考になればと思います。最初の方の表を使います(2番目でも同様ですが)。VBA がどうこうを超えてしまってますので、ま、適当に流してください。 まず、難解にしている要因として、管理表の形が厳しいのだと思います。ちょっと変形してみます。 まず、表1としては       A列  B列  C列  D列  E列  F列  G列 ------------------------------------------------------------------------ 1行目       4月  4月  4月  4月  4月  4月             10  11  12  13  14  15      ----------------------------------------------------------------- 2行目 社員A   23 3行目 社員B 4行目 社員C        4   15                  :         : ●行目 社員Y ●行目 社員Z                       11 ------------------------------------------------------------------------ 表がこうであれば、単純に縦計を出せば簡単ですよね。各コードごとにカラム(横)位置は固定して日付だけ入れているようなものです。 コードと日数で管理する場合は、これはデータベースのデータとして、表2としてこんな表になる方が望ましいのだと思います。 社員  コード  日数 ----------------------- A    10  23 C    12  15 C    11   4 Z    15  11 すべての社員の1コードのデータごとに1行にするということです。こうすると、コードでソート・グループ化すれば、集計は容易ですよね(月も項目として入るべきですが)。 この2つの形式がごっちゃになってしまって、難解にしてしまっているのだと思います。 ----- なので、出来れば元のシートを一旦、このどちらかの表の形に整形してしまったほうが良いです。その後のいろいろな解析等考えると表2のデータベース形式のほうが良いのですが、目的さえ達すればいいのであれば、表1の表のほうが楽です。 表1に成形するには、ちょっと抽象的なコードで書きますが、   ' 縦方向(社員分)のループ。社員が最大 100 だとします。2 とうのは2行目からの意味。   for Row = 2 to 2+100 - 1     ' 横方向(コード,日数)のループ。コードが最大 20 だとします 2 というのは B 列の意味。     for Col = 2 to 2+20*2 - 1 Step 2       ' 元のシートでコードが入っているかをチェックします       if 元のシート.Cells(Row, Col) <> "" then         '新しいシートに値を入れます。縦方向は同じで、横方向はコードから決め、決まった位置に日数を入れます。         新しいシート.Cells(Row, 元のシート.Cells(Row, Col)-10+1) = 元のシート.Cells(Row, Col+1)       endif     next   next こんな感じで成形すると、新しいシートに表1の形式が出来上がります(ほんとに数値だけの表になりますが)。後は縦計を取れば、目的の値が出てきますので、Excel の集計関数で十分ですよね。新しいシートでなくても、同じシートでずーっと下の方だったり、横のほうだったりを作業場所に使ってもいいと思います。 ちなみにここで一つ困るのは、コードが 10 からの連番という前提になっていることです。これが前提で無い場合は、コードを渡すと横位置を返すような関数をひとつ作ってあげると、いいかもしれません。 ----- 表2のほうに成形する場合は、こんな感じになるかと思います。   Row2 = 1 ' 新しい表の方の縦方向位置   ' 縦方向(社員分)のループ。社員が最大 100 だとします   for Row = 2 to 2+100 - 1     ' 横方向(コード,日数)のループ。コードが最大 20 だとします     for Col = 2 to 2 + 20*2 - 1 Step 2       ' 元のシートでコードが入っているかをチェックします       if 元のシート.Cells(Row, Col) <> "" then         '新しいシートに値を入れます。縦方向はRow2を使います。         '社員、コード、日数は元の表から持ってきます         新しいシート.Cells(Row2,1) = 元のシート.Cells(Row, 1) ' 社員         新しいシート.Cells(Row2,2) = 元のシート.Cells(Row, Col)) ' コード         新しいシート.Cells(row2,3) = 元のシート.Cells(Row, Col+1)) ' 日数         Rows2 = Rows2 + 1 ' 行をひとつ進めます       endif     next   next こんな感じになるかと思います。 表1は Excel の表として扱いやすい形、表2はデータベースとしていろいろ利用可能な形になります。表2できちんと月まで入っていれば、ピボットテーブルなどなどへの応用なども効くので、後々便利ではありますが、集計にはもうワンステップ必要ですね(ピボット作ってしまえばいいのですが)。 と、ちょっとした講義でした。求めている答えとはちょっと違っていてごめんなさいね。ちょっと自分だけで楽しんでしまいました!(笑)。

mont___blanc
質問者

お礼

ありがとうございます! ベストアンサーはjcctairaさんとさせて頂きましたが、データーベース自体を操作するという発想は大切にしていきたいと思いました。なにしろ、今回は日数を人ごと、コードごとに管理するという目的でしたが、上司から今後様々なデータ加工の依頼が来ると考えれば、加工しやすいデータを用意しておく必要があります。 本日、ご教授いただいた方法でデータベースの加工にチャレンジしてみます!

  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.2

初心者の域を脱していると推察しますが、より簡便なコードを模索されている様なので、重くて誰も褒めてくれないと思われるコードを投稿させていただきます。ご参考まで。 Sub test() Dim targetRange As Range, fieldNameRange As Range Dim myRow As Range, hitCell As Range Dim i As Long With Sheets("Sheet1") Set fieldNameRange = Range(.Range("G1"), .Cells(1, .Columns.Count).End(xlToLeft)) Set targetRange = .Range("A2:F6000") For Each myRow In targetRange.Rows For i = 1 To targetRange.Columns.Count - 1 Step 2 If myRow.Cells(i).Value <> "" Then Set hitCell = fieldNameRange.Find(myRow.Cells(i).Value, LookAt:=xlWhole) If Not hitCell Is Nothing Then .Cells(myRow.Row, hitCell.Column).Value = myRow.Cells(i + 1).Value End If End If Next i Next myRow End With End Sub

mont___blanc
質問者

お礼

ありがとうございます! こんな風に他の方の記述を見るのは勉強になります。 特に、mitarashiさんのご回答は、エクセル上のデータ範囲などが変更されても修正しやすいのかな?と思いましたが、どうなのでしょう? 今から実践してみます!

関連するQ&A