0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Excel-VBAで1週間分の勤怠データをまとめて表示する。

Last updated at Posted at 2023-04-16

■やりたいこと

 
・1週間分の勤怠データをまとめて表示する
 1シート事に1日の工数データが記載された全シートのデータを1週間分にまとめて、”Summary”シートに出力する。
 実装は1項目のデータに対してクラス設計を用い、後で例として分かりやすくしておく。
 (教育用の適当なサンプルとして後で使えるようにしたいため)

・例:1日の工数データ
image.png

・例:1週間分の勤怠データをまとめて表示
image.png

##■作った動機:12/20追記
新しい職場に着任して最初に気が付いた事は、工数管理に時間がかかっている事だった。
工数は手作業で2重管するという、劣悪な環境となっていたのだった。(*´Д`)
またこれによりミスが発生しやすく工数の修正に、工数を消費していた。
そのため業務が忙しい時には、工数管理が重なりさらに忙しくなる悪循環に陥っていた。
そんな状況下で、ある日突然3重となる工数管理が追加された。もはや誰の目にも無理だということは
明らかであった。

##■工数
設計5H
実装3H

■環境:

Environment:
Microsoft Excwl 2019

■実装(module.vbs)

①1項目のデータに対してクラス設計
 1項目のデータに以下のメンバー変数(Property)を設定する
 名前
 項目
 コスト
 日付

csItemcost.vbs
Option Explicit

' メンバ変数(非公開)
Private pvSt_Name As String
Private pvSt_Item As String
Private pvLng_Cost As String
Private pvd_dd As Date
Public csData As csItemcost

' メソッド(公開)
Public Property Let Name(ByVal value As String)
    pvSt_Name = value
End Property
 
Public Property Get Name() As String
 
    Name = pvSt_Name
    
End Property

Public Property Let Item(ByVal value As String)
 
    pvSt_Item = value
 
End Property
 
Public Property Get Item() As String
 
    Item = pvSt_Item
    
End Property

Public Property Let Cost(ByVal value As String)
 
    pvLng_Cost = value
 
End Property
 
Public Property Get Cost() As String
 
    Cost = pvLng_Cost
    
End Property

Public Property Let Dd(ByVal value As Date)
 
    pvd_dd = value
 
End Property
 
Public Property Get Dd() As Date
 
    Dd = pvd_dd
    
End Property

2.勤怠データ作成して、「Summary」シートにデータ出力するまでのを作成する。

module.vbs
Option Explicit
'公開変数
Public lng_endsellrow As Long     '最終行情報
Public myDic As Object            '勤怠データ(Dictionary型)
Public myDicOut As Object         'ソート後の勤怠データ(Dictionary型)

Sub Restore()
    Dim lng_i, lng_j As Long
    Dim tid As Long
    Dim p As csItemcost
    Dim ws As Worksheet
    Dim td As Date
    Dim st_nameexist As String
    
    '初期化
    Set myDic = CreateObject("Scripting.Dictionary")
    Set myDicOut = CreateObject("Scripting.Dictionary")
    tid = 1

    '----------------------------------------------------------------------------------------------
    ''勤怠データ作成
    '----------------------------------------------------------------------------------------------
    For Each ws In ThisWorkbook.Worksheets
        
        If ws.Name = "Summary" Then
            Exit For
        End If
        
        st_nameexist = ""
        td = ws.Cells(1, 3)
        If IsDate(ws.Cells(1, 3)) Then
            '最終行の取得
            lng_endsellrow = ws.Cells(Rows.Count, 1).End(xlUp).Row
            For lng_i = 2 To 6
                If lng_endsellrow < ws.Cells(Rows.Count, lng_i).End(xlUp).Row Then
                   lng_endsellrow = ws.Cells(Rows.Count, lng_i).End(xlUp).Row
                End If
            Next lng_i
            
            'データ取得
            For lng_j = 6 To lng_endsellrow
                
                If ws.Cells(lng_j, 2) <> "" And st_nameexist = "" Then
                    'フルデータ
                    st_nameexist = ws.Cells(lng_j, 2) '
                    
                    Set p = New csItemcost
                    p.Name = st_nameexist
                    p.Item = CStr(ws.Cells(lng_j, 3))
                    p.Cost = CStr(ws.Cells(lng_j, 4))
                    p.Dd = td
                    myDic.Add CStr(tid), p  'Noをキーにクラスを読み込み
                    Set p = Nothing
                    
                    tid = tid + 1
                ElseIf ws.Cells(lng_j, 2) = "" And ws.Cells(lng_j, 3) <> "" And ws.Cells(lng_j, 4) <> "" Then
                    Set p = New csItemcost
                    p.Name = st_nameexist
                    p.Item = CStr(ws.Cells(lng_j, 3))
                    p.Cost = CStr(ws.Cells(lng_j, 4))
                    p.Dd = td
                    myDic.Add CStr(tid), p  'Noをキーにクラスを読み込み
                    Set p = Nothing
                    
                    tid = tid + 1
                ElseIf ws.Cells(lng_j, 2) = "" And ws.Cells(lng_j, 3) = "" And ws.Cells(lng_j, 4) = "" Then
                   '初期化キャンセル
                   st_nameexist = "" '
                End If
              
            Next lng_j
        End If
    Next ws
    
    '----------------------------------------------------------------------------------------------
    ''データの入れ替え(名前でソート)
    '----------------------------------------------------------------------------------------------
    Dim olddd As Date
    Dim oldName As String
    Dim lng_ii As Long

    '初期化
    olddd = myDic(CStr(1)).Dd   '日付の初期化
    oldName = myDic(CStr(1)).Name
    lng_ii = 1                 '設定行の初期化

    For lng_i = 1 To tid - 1 '最終データまで
        'データの表示
        If oldName = myDic(CStr(lng_i)).Name Then
            If myDicOut.Exists(CStr(lng_ii)) = False Then  'データが存在していない
                Call SubSetcsItemcost1(lng_i, lng_ii)
               '行
               lng_ii = lng_ii + 1
            End If
        Else
            For lng_j = lng_i To tid - 1 '最終データまで
                If oldName = myDic(CStr(lng_j)).Name And myDicOut.Exists(CStr(lng_ii)) = False Then '同じ名前でデータが存在していない
                    Call SubSetcsItemcost1(lng_j, lng_ii)
                    '行
                    lng_ii = lng_ii + 1
                End If
            Next lng_j
            If myDicOut.Exists(CStr(lng_ii)) = False Then  'データが存在していない
                Call SubSetcsItemcost1(lng_i, lng_ii)
                Set p = Nothing
                '行
                lng_ii = lng_ii + 1
            End If
        End If

        '前回値
        olddd = myDic(CStr(lng_i)).Dd      '日付
        oldName = myDic(CStr(lng_i)).Name  'Name
    Next lng_i
    
    '----------------------------------------------------------------------------------------------
    ''「Summary」シート作成
    '----------------------------------------------------------------------------------------------
    ' 新しいシートを作成して、名前を「Summary」にする
    Dim summarySheet As Worksheet
    Dim sheetName As String
    Dim sheetExists As Boolean
    
    sheetName = "Summary"
    sheetExists = False
    
    ' シート名が「Summary」のシートが既に存在するかどうかを判定する
    For Each ws In ThisWorkbook.Worksheets
        If ws.Name = sheetName Then
            sheetExists = True
            Exit For
        End If
    Next ws
    
    ' もし同じ名前のシートが存在する場合は、それを削除する
    If sheetExists Then
        Application.DisplayAlerts = False
        ThisWorkbook.Worksheets(sheetName).Delete
        Application.DisplayAlerts = True
    End If
    
    ' 最後に「Summary」シートを作成する
    Set summarySheet = ThisWorkbook.Worksheets.Add(After:=Worksheets(Worksheets.Count))
    summarySheet.Name = sheetName
   
    ' 処理が完了したら、「Summary」シートをアクティブにする
    summarySheet.Activate

    '----------------------------------------------------------------------------------------------
    ''「Summary」シートにデータ出力
    '----------------------------------------------------------------------------------------------
    Dim t_offset As Long
    Dim b_Itemflg As Boolean '初日以降:True,初日:False
    Dim b_ItemNonExist As Boolean '存在:False,存在しない:True
    Dim l_start As Long      '人毎のデータ開始位置
   
    summarySheet.Cells(1, 1).value = "名前"
    summarySheet.Cells(1, 2).value = "項目"
    summarySheet.Cells(1, 3).value = "コスト"
    summarySheet.Cells(1, 4).value = "日付"

    '初期化
    olddd = myDicOut(CStr(1)).Dd   '日付の初期化
    lng_ii = 1                 '設定行の初期化
    l_start = 1
    t_offset = 4
    b_Itemflg = False
    b_ItemNonExist = True '存在しない
    oldName = myDicOut(CStr(1)).Name

    For lng_i = 1 To tid - 1 '最終データまで

        '日付の変更
        If olddd <> myDicOut(CStr(lng_i)).Dd Then
           t_offset = t_offset + 1 '日付のカラム位置
           b_Itemflg = True
        End If
        
        '名前の変更
        If oldName <> myDicOut(CStr(lng_i)).Name Then
            t_offset = 4
            l_start = lng_ii
            b_Itemflg = False
            b_ItemNonExist = True
        End If

        ''データの表示
        '初日以降なら項目を探す
        If b_Itemflg Then
            For lng_j = l_start To lng_i '
                If summarySheet.Cells(lng_j + 2, 2) = myDicOut(CStr(lng_i)).Item Then
                    summarySheet.Cells(lng_j + 2, t_offset) = myDicOut(CStr(lng_i)).Cost
                    b_ItemNonExist = False '項目が存在
                End If
            Next lng_j
            If b_ItemNonExist Then
                Call SubSetcsItemcost2(summarySheet, lng_ii, t_offset, lng_i)
                '行の初期化
                lng_ii = lng_ii + 1
            End If
            b_ItemNonExist = True
        Else
            Call SubSetcsItemcost2(summarySheet, lng_ii, t_offset, lng_i)
            '行の初期化
            lng_ii = lng_ii + 1
        End If
        summarySheet.Cells(2, t_offset) = myDicOut(CStr(lng_i)).Dd '日付
        '前回値
        olddd = myDicOut(CStr(lng_i)).Dd     '日付
        oldName = myDicOut(CStr(lng_i)).Name 'Name
    Next
End Sub


'----------------------------------------------------------------------------------------------
' 関数:csItemcost型データの入力
' csItemcost > myDic
'----------------------------------------------------------------------------------------------
Sub SubSetcsItemcost1(ByVal lng_out As Long, ByVal lng_in As Long)
    Dim p As csItemcost

    Set p = New csItemcost
    p.Name = myDic(CStr(lng_out)).Name
    p.Item = myDic(CStr(lng_out)).Item
    p.Cost = myDic(CStr(lng_out)).Cost
    p.Dd = myDic(CStr(lng_out)).Dd
    
    myDicOut.Add CStr(lng_in), p  'Noをキーにクラスを読み込み
    Set p = Nothing
End Sub
'----------------------------------------------------------------------------------------------
' 関数:summarySheetへデータ出力
' myDicOut > summarySheet
'----------------------------------------------------------------------------------------------
Sub SubSetcsItemcost2(summarySheet As Worksheet, ByVal lng_in As Long, ByVal lng_offset As Long, ByVal lng_out As Long)

    summarySheet.Cells(lng_in + 2, 1) = myDicOut(CStr(lng_out)).Name
    summarySheet.Cells(lng_in + 2, 2) = myDicOut(CStr(lng_out)).Item
    summarySheet.Cells(lng_in + 2, lng_offset) = myDicOut(CStr(lng_out)).Cost

End Sub

以上です、お疲れ様です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?