[[20190929192243]] 『シフト作成、1 コードの添削宜しくお願い致しまax(なのれい) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『シフト作成、1 コードの添削宜しくお願い致します。』(なのれい)

いつもお世話になっております。

皆様ご存じだと思うんですが、シフト作成を行っております。
自分のコードが甘いので添削して頂けないでしょうか?
宜しくお願い致します。

条件
・連続勤務6日以下になる事
・休み(公)の前日は早番(A)、次の日は遅番(B)
・月の公休は6日間
・出勤のサイクルとしてBA公の順になる
例 BBBAA公BBA公BAA
ABのパターンにはならないってことです。
・上記条件に当てはまらない従業員も数名います。
・希望休を手入力するタイミングが欲しい

前回との変更点
・上記条件の場合だと、最小勤務日数が2日間になるのでこれを3日間にしたい。

	C	D	E	F	G	H	I	J	K																											
6	2019	10	月			1	2	3	4	5	6	7	8	9	10	11	12	13	14	15	16	17	18	19	20	21	22	23	24	25	26	27	28	29	30	31
7						火	水	木	金	土	日	月	火	水	木	金	土	日	月	火	水	木	金	土	日	月	火	水	木	金	土	日	月	火	水	木
8	名前						入替																													
9	佐藤																														B	A	公	B	B	A
10	工藤																														B	B	A	A	A	公
11	伊藤																														A	公	B	B	B	A
12	加藤																														公	B	A	A	公	B

1日から25日は省略しています。
下方向に氏名、右方向に日にち、は決まりです。また日にちの下の行は曜日、その下の行は(入替)を入力する行が必要になります。

添削して頂きたいコード
Sub Macro4()
Dim 氏名最終行 As Long, 末日 As Long, i As Long

    With Worksheets("作成シート")
    氏名最終行 = Range("C6").End(xlDown).Row
    末日 = Cells(4, Columns.Count).End(xlToLeft).Column

    Range("D7:L" & 氏名最終行).Clear
    Range(Cells(7, 末日), Cells(氏名最終行, 末日)).Copy Range("G7")

        For i = 7 To 氏名最終行
            最終公休日 = Range(i & ":" & i).Find(What:="公", SearchDirection:=xlPrevious).Column
            月末連勤数 = 末日 - 最終公休日
            Cells(i, 6).Value = 月末連勤数

            If Cells(i, 7) = "B" Then
                Cells(i, 8).Value = "出"
            End If

            If Cells(i, 6) <= "2" Then
                Cells(i, 8).Value = "出"
                If Cells(i, 6) <= "1" Then
                    Cells(i, 9).Value = "出"
                    If Cells(i, 6) <= "0" Then
                        Cells(i, 10).Value = "出"
                    End If
                End If
            End If
        Next i

        If Range("D4").Value < 12 Then
            Range("D4") = Range("D4") + 1
        Else
            Range("D4") = 1
            Range("C4") = Range("C4") + 1
        End If
        Range("L7:AL" & 氏名最終行).Clear
    End With
End Sub

問題点
末日 = Cells(4, Columns.Count).End(xlToLeft).Column
最後の列を取得したいんですが、30日の月も31日に数式が入っている状態ですので31の列を取得してしまいます。ここを30の列を取得したいです。
31のセルには=IFERROR(IF(EOMONTH(AK4,0)=EOMONTH(AK4+1,0),AK4+1,""),"")が入っております。

そのほかは問題なく動いておりますが、もっと簡潔に出来るのなら簡潔にしたいです。
添削宜しくお願い致します。

< 使用 Excel:unknown、使用 OS:unknown >


説明不十分で申し訳ありません。

今月のシフトが入ってる状態から来月のシフトを作成していきます。
まず上記のコードを行いたいという事です。
上記のコードが終わったら、希望休を手入力で入れていく予定です。
(なのれい) 2019/09/29(日) 21:35


>最後の列を取得したいんですが、30日の月も31日に数式が入っている状態ですので
>31の列を取得してしまいます。ここを30の列を取得したいです。
年、月が決まっているなら、ワークシートの入力がどうであろうと、
月末日は決まっているので、それで最終列が決まるのでは?

(γ) 2019/09/30(月) 00:11


質問とは違う部分でが気になったので先に。

■1
Withステートメントを使っているけど、.が無いから意味がなくなっている。

■2
↓は

    If Cells(i, 6) <= "2" Then
        Cells(i, 8).Value = "出"
        If Cells(i, 6) <= "1" Then
            Cells(i, 9).Value = "出"
            If Cells(i, 6) <= "0" Then
                Cells(i, 10).Value = "出"
            End If
        End If
    End If

こういう書き方もありでは?

 (なぜか文字列を比較していたので直しました)         
    If Cells(i, 6) <= 2 Then
        Cells(i, 8).Value = "出"
    ElseIf Cells(i, 6) <= 1 Then
        Cells(i, 9).Value = "出"
    ElseIf Cells(i, 6) <= 0 Then
        Cells(i, 10).Value = "出"
    End If

で、整理すると、「1」「0」「-1以下(あるのかわからないけど)」も、「f Cells(i, 6) <= 2 Then」が真になるから、 ElseIfの部分の意味がなくなってます

■3-1
質問の方は月末日の列を取得したいのですよね?
VBAで月末日を取得する方法の1例は、前トピックで示してますよ。

 ↓より抜粋
[[20190914110320]] 『CALLでプログラムを呼ぶと上手く処理されない』(なのれい)
(もこな2 ) 2019/09/27(金) 19:08

 '▼シリアル値から月末日を数値で算出
 月末日 = Day(DateSerial(Year(Range("H5")), Month(Range("H5")) + 1, 0))

■3-2
したがって、1日が入ってる列(例えばH列)から.offset(,月末日-1)すれば、月末の列ですね。

 .Cells(i, "H").Offset(, 月末日-1) 

前トピックでは、セルの集まりを掴みたかったので↓みたいに示しましたが。

 '▼1日〜月末までループ処理
 For Each MyRNG In .Cells(i, "H").Resize(, 月末日)

(もこな2) 2019/09/30(月) 00:38


横から失礼します。
コードのうち4行目になっているのは6行目の間違いだろうと思います。

あと最終連勤数周りがまわりくどいように見えます。
わざわざ最終連勤を出したいというのでもなければ
月初3勤を出すのに末日をシフトをG列に持って来たりF列に最終連勤数を出したりしなくても
if 末日が「公」 then 8,9,10列目は「出」
elseif 末日の一つ左が「公」 then 8.9列目は「出」
elseif 末日の二つ左が「公」か末日が「B」 then 8列目は「出」
という式で十分なように見えます。
(黄色い循環参照) 2019/09/30(月) 01:35


書き込んだあとに見直してみたらおかしなことを書いているのに気付きました。
希望休や不規則シフトにも対応するために連勤数や最終シフトから人力検討もするのですね。
上記部分は無視してください。すみません。
(黄色い循環参照) 2019/09/30(月) 01:42

そうですね!
4行目、6行目間違ってます。
4行目が日にちの行になります。
失礼いたしました。

Sub Macro4()
Dim 氏名最終行 As Long, 月末日 As Long, i As Long

    With Worksheets("作成シート")
    氏名最終行 = Range("C6").End(xlDown).Row
    月末日 = Format(DateSerial(Year(Date), Month(Date), 0), "d") + 7

    Range("D7:L" & 氏名最終行).Clear

        For i = 7 To 氏名最終行
            Cells(i, 7).Value = 月末日 - Range(i & ":" & i).Find(What:="公", SearchDirection:=xlPrevious).Column

            If Cells(i, 月末日) = "B" Then
                Cells(i, 8).Value = "出"
            End If

            If Cells(i, 7) <= 2 Then
                Cells(i, 8).Value = "出"
                If Cells(i, 7) <= 1 Then
                    Cells(i, 9).Value = "出"
                    If Cells(i, 7) <= 0 Then
                        Cells(i, 10).Value = "出"
                    End If
                End If
            End If
        Next i

        If Range("D4").Value < 12 Then
            Range("D4") = Range("D4") + 1
        Else
            Range("D4") = 1
            Range("C4") = Range("C4") + 1
        End If
        Range("L7:AL" & 氏名最終行).Clear
    End With
End Sub

また説明不足でした。(出)は出勤確定で、後々(A)(B)のどちらかを入れるつもりです。

コード修正致しました。
変更した点
・今月末の最終列を取得
・今月末のシフトが(B)なら1日の列を(出)にする
・最終日のシフトを省いたので、Cells(i, 7)に連勤の日数を持ってきました。

■1 今回のコードの場合、Withステートメントは必要ないですか?

■2は上手く行かなったので現状のままにしております。

■3月末の日は上記のコードで解決出来てると思っております。どうでしょうか?


(なのれい) 2019/09/30(月) 02:57


>■1 今回のコードの場合、Withステートメントは必要ないですか?
ご自身で決めてください。

ただ、標準モジュールに記述しているなら、↓のようなことになってます。

    With Worksheets("あいう")

        Range("A1").Value = ""
        '↓「.」をつけ忘れるとこうなる
        ActiveSheet.Range("A1").Value = ""

        .Range("A1").Value = ""
        '↓ちゃんと「.」をつけるとこうなる
        Worksheets("あいう").Range("A1").Value = ""

    End With

前に提示したような気もしますが、参考です。
http://officetanaka.net/excel/vba/beginner/16.htm

>■2は上手く行かなったので現状のままにしております。
なにがどう上手く行かなったかわかりませんが、↓をステップ実行してなんでC1セルではなく、B1セルに書き込まれるのか考えてみてください。

    Sub 実験用8()

        Range("A1").Value = 1

        If Range("A1").Value <= 2 Then
            Cells(1, "B").Value = "出"

        ElseIf Range("A1").Value <= 1 Then
            Cells(1, "C").Value = "出"

        ElseIf Range("A1").Value <= 0 Then
            Cells(1, "D").Value = "出"

        End If

    End Sub

>■3月末の日は上記のコードで解決出来てると思っております。どうでしょうか?

                                実行日       実行日   0 
                                  ↓           ↓    ↓
 月末日 = Format(DateSerial(Year(Date), Month(Date), 0), "d")

なので、2019/9/30に実行したら、 2019/9/0 → 2019/8/31 → 31 になりますね。
(コード上では実際には何故か7足してますけど)

マクロを動かした日からみて先月末日を知りたいなら正解?ですかね。
まぁ、ご自身で試しているのでしょうから問題なければいいんじゃないですか?
私なら、前トピックのように、カレンダーから対象の年月日を取得します。

■4 Findメソッドについて
指摘し飽きましたけど、LookIn や LookAtが省略されてますね。大丈夫ですか?
また、見つからなかった場合↓みたいになり、実行時エラーになりますけど大丈夫ですか?

 月末日 - Nothing.Column

■5 SearchDirectionについて
ただの興味本位で聞きますが、なんでSearchDirectionを指定したのですか?

 SearchDirection  前方に検索(xlNext:既定値)、後方に検索(xlPrevious)[省略可能]

(もこな2) 2019/09/30(月) 05:22


■1
シートの移動しないのでWithステートメントは使用しなくても大丈夫だと思ってます。

■2
これに関してはちょっと簡略に出来そうなので考え直してきます。

■3
これに関しては実行月の月末日が出ると思っております。
月末日 = Format(DateSerial(Year(Date), Month(Date) + 1, 0), "d") + 7
これで今月末の最終日になります。
7を足してる理由は、30日だと列が37番目、31日だと38番目になるためです。

■4
これに関してですが、”公”が無いってことは休みが無いって事だと思います。
さすがにそれはないので問題無いと思ってるのですが、やはり必要なんでしょうか?

■5
これはネットからコピペして上手くいったのもので、一番右の”公”を探してると思っております。

(なのれい) 2019/09/30(月) 07:18


■2は上手く行かなったので現状のままにしております。
なにがどう上手く行かなったかわかりませんが、↓をステップ実行してなんでC1セルではなく、B1セルに書き込まれるのか考えてみてください。

0の場合は1〜3まで出
1の場合は1〜2まで出
2の場合は1が出

にしたいので提示頂いたものですと、2日、3日のい処理が出来ないと思います。

(なのれい) 2019/09/30(月) 08:31


Sub Macro4()
Dim 氏名最終行 As Long, 月末日 As Long, i As Long
    氏名最終行 = Range("C6").End(xlDown).Row
    月末日 = Format(DateSerial(Year(Date), Month(Date) + 1, 0), "d") + 7

    Range("D7:L" & 氏名最終行).Clear

        For i = 7 To 氏名最終行
            Cells(i, 7).Value = 月末日 - Range(i & ":" & i).Find(What:="公", LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious).Column

            If Cells(i, 月末日) = "B" Then
                Cells(i, 8).Value = "出"
            End If

            If Cells(i, 7) <= 2 Then
                Cells(i, 8).Value = "出"
                If Cells(i, 7) <= 1 Then
                    Cells(i, 9).Value = "出"
                    If Cells(i, 7) <= 0 Then
                        Cells(i, 10).Value = "出"
                    End If
                End If
            End If
        Next i

        If Range("D4").Value < 12 Then
            Range("D4") = Range("D4") + 1
        Else
            Range("D4") = 1
            Range("C4") = Range("C4") + 1
        End If
        Range("L7:AL" & 氏名最終行).Clear
End Sub

現在修正かけて上記のコードになっております。
(なのれい) 2019/09/30(月) 08:42


Option Explicit
Sub 月末連勤チェックと月初めシフト()
Dim 氏名最終行 As Long, 月末日 As Long, i As Long
    氏名最終行 = Range("C6").End(xlDown).Row
    月末日 = Format(DateSerial(Year(Date), Month(Date) + 1, 0), "d") + 7

    Range("D7:L" & 氏名最終行).Clear

        For i = 7 To 氏名最終行
            Cells(i, 7).Value = 月末日 - Range(i & ":" & i).Find(What:="公", LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious).Column

            If Cells(i, 月末日) = "B" Then
                Cells(i, 8).Value = "出"
            End If

        Next i

        If Range("D4").Value < 12 Then
            Range("D4") = Range("D4") + 1
        Else
            Range("D4") = 1
            Range("C4") = Range("C4") + 1
        End If
        Range("L7:AL" & 氏名最終行).Clear
End Sub

何度も申し訳ありません。消した場所あるんですが、当てはまらない従業員がいたので後に組み込む予定です。
とりあえず、上記でいかがでしょうか?

(なのれい) 2019/09/30(月) 09:49


Option Explicit
Sub 月末連勤チェックと月初めシフト()
Dim 氏名最終行 As Long, 月末日 As Long, i As Long
    With Worksheets("作成シート")
    氏名最終行 = .Range("C6").End(xlDown).Row
    月末日 = Format(DateSerial(Year(Date), Month(Date) + 1, 0), "d") + 7

    .Range("D7:L" & 氏名最終行).Clear

        For i = 7 To 氏名最終行
            .Cells(i, 7).Value = 月末日 - .Range(i & ":" & i).Find(What:="公", LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious).Column

            If .Cells(i, 月末日) = "B" Then
                .Cells(i, 8).Value = "出"
            End If

        Next i

        If .Range("D4").Value < 12 Then
            .Range("D4") = Range("D4") + 1
        Else
            .Range("D4") = 1
            .Range("C4") = Range("C4") + 1
        End If
        .Range("L7:AL" & 氏名最終行).Clear
    End With
End Sub

Withステートメントを使う場合はこうなるって事であってますか?

(なのれい) 2019/09/30(月) 10:06


.clearは書式も罫線も消してしまうので、値だけ消すなら.clearcontentsのほうがオススメです。

年月の情報を入力したセルがあるのですから、year(date)やmonth(date)ではなくそちらを活かしてはいかがでしょうか。

「公」の検索対象範囲は最大でもH〜AM列でしょうから、行全体ではなくそれだけにしても良いのではないかと思います。
またみなさんご指摘ですが、検索の結果Nothingだったときの処理は必要だと思います。
(mori) 2019/09/30(月) 10:13


.Range("D4") = Range("D4") + 1
.Range("C4") = Range("C4") + 1
「.」のつけ忘れはこの2つぐらいだと思います。
(mori) 2019/09/30(月) 10:20

.clearは書式も罫線も消してしまうので、値だけ消すなら.clearcontentsのほうがオススメです。

これに関して背景色が後々つくのでclearにしました。

年月の情報を入力したセルがあるのですから、year(date)やmonth(date)ではなくそちらを活かしてはいかがでしょうか。
これに関しては
月末日 = Format(DateSerial(.Range("C4"), .Range("D4") + 1, 0), "d") + 7
この様にしました。

「公」の検索対象範囲は最大でもH〜AM列でしょうから、行全体ではなくそれだけにしても良いのではないかと思います。
これに関しては
.Cells(i, 6).Value = 月末日 - .Range(Cells(i, 8), Cells(i, 月末日)).Find(What:="公", LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious).Column
この様にしました。

.Range("D4") = Range("D4") + 1
.Range("C4") = Range("C4") + 1
「.」のつけ忘れはこの2つぐらいだと思います。
こちら付けました。

検索の結果Nothingだったときの処理は必要だと思います。
Option Explicit
Sub 月末連勤チェックと月初めシフト()
Dim 氏名最終行 As Long, 月末日 As Long, i As Long
Dim 最終公休日 As Range

    With Worksheets("作成シート")
    氏名最終行 = .Range("C6").End(xlDown).Row
    月末日 = Format(DateSerial(.Range("C4"), .Range("D4") + 1, 0), "d") + 7

    .Range("D7:L" & 氏名最終行).Clear
    .Range(Cells(7, 月末日), Cells(氏名最終行, 月末日)).Copy Range("G7")

        For i = 7 To 氏名最終行

            最終公休日 = .Range(Cells(i, 8), Cells(i, 月末日)).Find(What:="公", LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious).Column

            If Not (最終公休日 Is Nothing) Then
            .Cells(i, 6).Value = 月末日 - 最終公休日

                If Cells(i, 7) = "B" Then
                    Cells(i, 8).Value = "出"
                End If
            End If

        Next i

        If .Range("D4").Value < 12 Then
            .Range("D4") = .Range("D4") + 1
        Else
            .Range("D4") = 1
            .Range("C4") = .Range("C4") + 1
        End If
        .Range("L7:AL" & 氏名最終行).Clear
    End With
End Sub

何度もコード変わって申し訳ありません。

Nothingの処理はこんな感じにしないといけないとは思ってるんですが、やはり理解できない状態です。
すみません。

(なのれい) 2019/09/30(月) 11:25


そのコードでは、検索結果がNothingだったときに
最終公休日がNothingの.columnを取得しようとしてその時点でエラーになってしまいます。
あと、findは最初のセル番地の次から検索するという特徴があるので、月末日から探すのであればもう少し工夫が必要です。
おまけですが、いくつかのcellsの前の「.」がまた抜けてしまっています。
(mori) 2019/09/30(月) 11:39

また、「最終公休日」変数の宣言がrange型でされているのに、「set」抜きで代入しようとしているので
その点でもエラーになります。
現状では変数「最終公休日」の扱いが混乱しているので整理しなければいけません。

変数「最終公休日」をrange型にするのであれば代入時に.columnを省いて
列の値として計算したいときに「最終公休日.column」とするか
変数「最終公休日」をlong型(またはinteger型等)にするのであれば
「not 最終公休日 is nothing 」という式ではなく違ったものにしなければなりません。
(mori) 2019/09/30(月) 12:15


Option Explicit
Sub 月末連勤チェックと月初めシフト()
Dim 氏名最終行 As Long, 月末日 As Long, i As Long, 最終公休日123 As Long
Dim 最終公休日 As Range
    With Worksheets("作成シート")
    氏名最終行 = .Range("C6").End(xlDown).Row
    月末日 = Format(DateSerial(.Range("C4"), .Range("D4") + 1, 0), "d") + 7

    .Range("D7:L" & 氏名最終行).Clear
    .Range(Cells(7, 月末日), Cells(氏名最終行, 月末日)).Copy Range("G7")

        For i = 7 To 氏名最終行

            Set 最終公休日 = .Range(Cells(i, 8), Cells(i, 月末日)).Find(What:="公", LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious)

            If Not (最終公休日 Is Nothing) Then

            .Cells(i, 6).Value = 月末日 - Format(最終公休日.Column, "#,##0")

                If .Cells(i, 7) = "B" Then
                    .Cells(i, 8).Value = "出"
                End If
            End If

        Next i

        If .Range("D4").Value < 12 Then
            .Range("D4") = .Range("D4") + 1
        Else
            .Range("D4") = 1
            .Range("C4") = .Range("C4") + 1
        End If
        .Range("L7:AL" & 氏名最終行).Clear
    End With
End Sub

こちらでいかがでしょうか?
一応問題なく処理はされています。
(なのれい) 2019/09/30(月) 13:00


あとは
セル参照なのかセルの値への参照なのかの整理
「『作成シート』のセルを参照する」ところに「.」をつけているかの確認
使われていない変数の整理
無意味な処理の整理
字下げの整理
をすると良いと思います。
(mori) 2019/09/30(月) 14:22

 お腹一杯かもしれませんが、

 ・ドットの漏れがまだたくさんあるようです。試しに"作成シート" 以外のシートを前面にして
 コードを実行してみてください。回答者の皆さんの指摘している意味がわかると思います。

 ・.Value を書いたり書かなかったり、統一したほうがいいと思います

 ・Findメソッドは Afterをきちんと指定しないと 誤動作するのでは?

 ・ .Cells(i, 6).Value = 月末日 - Format(最終公休日.Column, "#,##0")
 これは なぜFormatを使っているのですか? 
 月末列 - 最終公休日セル.Column
 でいいと思います。

 最後に
 >        If .Range("D4").Value < 12 Then
 >            .Range("D4") = .Range("D4") + 1
 >        Else
 >            .Range("D4") = 1
 >            .Range("C4") = .Range("C4") + 1
 >        End If

 ですが .Range("D4").Value が 1 だった場合でも 最初の処理しか走りませんよ

(渡辺ひかる) 2019/09/30(月) 15:18


Option Explicit
Sub 月末連勤チェックと月初めシフト()
Dim 氏名最終行 As Long, 月末日 As Long, i As Long
Dim 最終公休日 As Range
    With Worksheets("作成シート")
    氏名最終行 = .Range("C6").End(xlDown).Row
    月末日 = Format(DateSerial(.Range("C4"), .Range("D4") + 1, 0), "d") + 7

    .Range("D7:L" & 氏名最終行).Clear
    .Range(.Cells(7, 月末日), .Cells(氏名最終行, 月末日)).Copy .Range("G7")

        For i = 7 To 氏名最終行

            Set 最終公休日 = .Range(.Cells(i, 8), .Cells(i, 月末日)).Find(What:="公", LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious)

            If Not (最終公休日 Is Nothing) Then

            .Cells(i, 6).Value = 月末日 - 最終公休日.Column

                If .Cells(i, 7).Value = "B" Then
                    .Cells(i, 8).Value = "出"
                End If
            End If

        Next i

        If .Range("D4").Value < 12 Then
            .Range("D4").Value = .Range("D4") + 1
        Else
            .Range("D4").Value = 1
            .Range("C4").Value = .Range("C4") + 1
        End If
        .Range("L7:AL" & 氏名最終行).Clear
    End With
End Sub

修正したコードです。

ドットの漏れの修正
.Valueの修正
月末列 - 最終公休日セル.Columnの修正

上記をしました。

If .Range("D4").Value < 12 Then

 >            .Range("D4") = .Range("D4") + 1
 >        Else
 >            .Range("D4") = 1
 >            .Range("C4") = .Range("C4") + 1
 >        End If

これはこのままの処理で良いと思いますけど、何かおかしいですか?

・Findメソッドは Afterをきちんと指定しないと 誤動作するのでは?
これは

.Find(What:="公", After:=Range("G" & i), LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious)

.Find(What:="公", After:=Cells(i, 7), LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious)

の様に変更してみましたが、型が一致しませんとなりました。
何がいけないんでしょうか?

(なのれい) 2019/09/30(月) 15:54


書きためている間に順番が入り繰りになっちゃいましたが面倒なのでそのまま投稿します。

■6
表が見づらかったので整理してみました。
現状はこんな感じですよね

 【作成シート】のレイアウト
       1      2    3
   ____C______D____E___...___H____I____J____K_....__AG___AH___AI___AJ___AK___AL___                                                                                                           
6    2019    10    月        1    2    3    4       26   27   28   29   30   31
7                            火  水    木   金      土   日   月   火   水   木
8    名前                        入替               B    A    公   B    B    A
10   工藤                                           B    B    A    A    A    公
11   伊藤                                           A    公   B    B    B    A
12   加藤                                           公   B    A    A    公   B

■7
>これはネットからコピペして上手くいったのもので、一番右の”公”を探してると思っております。
>これに関してですが、”公”が無いってことは休みが無いって事だと思います。
>さすがにそれはないので問題無いと思ってる

なるほど、必ず検索範囲には「公」が1つ以上ある設計になっていて、複数ある場合は、一番最後(右)の「公」となっている"セル"を探したいのですね。
それなら、深く考えず元のまま行を丸ごと検索してしまえばよいとおもいます。(その場合、たぶんAfterは要らないです)

    Sub 実験12()
        Dim a As Range
        Set a = Rows(12).Find(What:="公", LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious)

        If Not a Is Nothing Then MsgBox "お探しのセルは【" & a.Address(0, 0) & "】です"
    End Sub

■8
>0の場合は1〜3まで出
>1の場合は1〜2まで出
>2の場合は1が出
>にしたいので提示頂いたものですと、2日、3日のい処理が出来ないと思います。

なるほど。そういう処理がしたかったのですね。
実験8は私が処理を勘違いしていたので、確かに希望の動作にはならないですね。ごめんなさい。
現状でも、問題は無いと思いますが、【ブランクセルの時は処理しない】&【数字はそ0〜2のいずれかしか入らない】ということであれば、前回のようにSelect Caseを使って

    Sub 実験9()
        Const i As Long = 2

        Select Case Cells(i, 6).Value
            Case Is = "2":  Application.Range(Cells(i, 8), Cells(i, 8)).Value = "出"
            Case Is = "1":  Application.Range(Cells(i, 8), Cells(i, 9)).Value = "出"
            Case Is = "0":  Application.Range(Cells(i, 8), Cells(i, 10)).Value = "出"
        End Select

    End Sub

とか、OffsetやResizeプロパティを使ってみるというアプローチもありそうです。

    Sub 実験10()
        Const i As Long = 2

        If Cells(i, 6).Value <> "" And Cells(i, 6).Value >= 0 And Cells(i, 6).Value <= 2 Then
            Application.Range(Cells(i, 8), Cells(i, 8).Offset(, 2 - Cells(i, 6).Value)).Value = "出"
        End If
    End Sub

    Sub 実験11()
        Const i As Long = 2

        If Cells(i, 6).Value <> "" And Cells(i, 6).Value >= 0 And Cells(i, 6).Value <= 2 Then
            Cells(i, 8).Resize(, 3 - Cells(i, 6).Value).Value = "出"
        End If

    End Sub

 ※実験9では「Case Is = 0」としてしまうと、ブランクセルも反応してしまうので意図的に文字列として判定しています。

(もこな2 ) 2019/09/30(月) 18:56


■6
表記ミスで4行目が日にちの行になります。

■7
これに関しては
Set 最終公休日 = .Range(.Cells(i, 8), .Cells(i, 月末日)).Find(What:="公", LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious)

If Not (最終公休日 Is Nothing) Then

この様にしております。

行全体を検索範囲にする必要が無いという指摘ありましたのでこの様にしています。

■8
これに関しては後々処理しますので、その時の参考にさせて頂きます。

ありがとうございます。

現在のコード
Option Explicit
Sub 月末連勤チェックと月初めシフト()
Dim 氏名最終行 As Long, 月末日 As Long, i As Long
Dim 最終公休日 As Range

    With Worksheets("作成シート")
    氏名最終行 = .Range("C6").End(xlDown).Row
    月末日 = Format(DateSerial(.Range("C4"), .Range("D4") + 1, 0), "d") + 7

    .Range("D7:L" & 氏名最終行).Clear
    .Range(.Cells(7, 月末日), .Cells(氏名最終行, 月末日)).Copy .Range("G7")

        For i = 7 To 氏名最終行

            Set 最終公休日 = .Range(.Cells(i, 8), .Cells(i, 月末日)).Find(What:="公", LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious)

            If Not (最終公休日 Is Nothing) Then

            .Cells(i, 6).Value = 月末日 - 最終公休日.Column

                If .Cells(i, 7).Value = "B" Then
                    .Cells(i, 8).Value = "出"
                End If
            End If

        Next i

        If .Range("D4").Value < 12 Then
            .Range("D4").Value = .Range("D4") + 1
        Else
            .Range("D4").Value = 1
            .Range("C4").Value = .Range("C4") + 1
        End If
        .Range("L7:AL" & 氏名最終行).Clear
    End With
End Sub

(なのれい) 2019/09/30(月) 20:13


 >の様に変更してみましたが、型が一致しませんとなりました。 
 > 何がいけないんでしょうか? 

 >After:=Cells(i, 7)

 Cellsの前のドットが抜けているとか?

 こちらで試したところ コード自体は、問題ありませんでした

 ただ、お詫びですが、私の認識に誤りがあり
 Afterを省略すると ActiveCellの次から検索すると思い込んでいたのですが
 ヘルプを見ると

 「この引数を省略すると、対象セル範囲の左上端のセルが検索の開始点になります。」

 とありましたので、今回の場合 検索範囲が一行だけで、左上端のセルから後方へ検索するので
 結果として、最終公休日になるということですね。

 ですから今回の場合は、省略しても問題はないようです。

 それと

 IF文については、私の勘違いでした すみません 条件文と処理文を取り違えていました。

(渡辺ひかる) 2019/10/01(火) 10:24


■9
>表記ミスで4行目が日にちの行になります。
では、こういうことでしょうか?
                                                                  28   29   30   31       ← H列から何列目か
                                                        33   34   35   36   37   38       ← 列番号
     ____C______D____E___...___H___I___J___K___L__....__AG___AH___AI___AJ___AK___AL__     ← 列文字
  4    2019    10    月        1   2   3   4   5        26   27   28   29   30   31
  5                            火  水  木  金  土       土   日   月   火   水   木
  6    名前                       入替                  B    A    公   B    B    A
  7    工藤                                             B    B    A    A    A    公
  8    伊藤                                             A    公   B    B    B    A
  9    加藤                                             公   B    A    A    公   B

■10
こちらも興味本位ですが、↓は何をしているのですか?

 .Cells(i, 6).Value = 月末日 - 最終公休日.Column

たとえば、■9でいうと↓みたいになりますが・・・

 E7  = 31+7-35 = 3
 E8  = 31+7-38 = 0
 E9  = 31+7-37 = 1

■11
年と月を入れる処理(月次更新)の部分は現状でも問題ないと思いますが、月末日をDate型として扱うなら↓のようにもできますね。

    Sub 実験13()
        Dim 月末日 As Date
        月末日 = DateSerial(Range("C4"), Range("D4") + 1, 0)

        MsgBox "今月の月末は" & Day(月末日) & "日です"

        '月次更新
        Range("C4").Value = Year(月末日 + 1)
        Range("D4").Value = Month(月末日 + 1)

    End Sub

■12
>行全体を検索範囲にする必要が無いという指摘ありましたのでこの様にしています。
何度か言っていると思いますが、方法の一つを案内しているつもりですので、絶対この方法にすべきという意味ではありません。取捨選択はご自身で行ってください。
言われたまま(分からないけど)採用するとした場合、ご自身でメンテナンスできなくなりますから、分かる(理解できた)方法を採用すべきです。

ちなみに、■11のように月末日をDate型にした場合は、↓のようにH列から月末日までの分、列を拡張するという考え方もありますね。(前トピックで示してましたが)

    Sub 実験14()
        Dim 月末日 As Date
        Dim 最終公休日 As Range
        Const i As Long = 7

        With ActiveSheet
            月末日 = DateSerial(Range("C4"), Range("D4") + 1, 0)
            Set 最終公休日 = .Cells(i, "H").Resize(, Day(月末日)).Find(What:="公", LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious)

            If Not 最終公休日 Is Nothing Then MsgBox "最終公休日のセルは【" & 最終公休日.Address(0, 0) & "】です"
        End With

    End Sub

■13
質問とは関係ないですが、この掲示板に投稿する際に、行頭に1文字以上の半角スペースを入れると、ちょっと小さめの文字で改行されなくなります。
(逆に、半角スペースを入れた次の行は、前の行に依存するので行が変わって元のように表示したい場合は1行空ける必要が出てきちゃいますが)

↓半角スペースなし

ああああ

↓半角スペースあり

 あああ

(もこな2) 2019/10/01(火) 12:25


■9
はい。 そういう事です。

■10
月末時点での出勤日数を確認しております。
月またぎでも7連勤務しない為の制御が必要と思い項目を設けております。

■11 ■12
こちらは現状で問題ないのであれば、このままいきたいと思います。

■13
わかりました。やってみます。

とりあえず、下記コードで完成で行きたいと思います。

 Sub 月末連勤チェックと月初めシフト()
Dim 氏名最終行 As Long, 月末日 As Long, i As Long
Dim 最終公休日 As Range
    With Worksheets("作成シート")
    氏名最終行 = .Range("C6").End(xlDown).Row
    月末日 = Format(DateSerial(.Range("C4"), .Range("D4") + 1, 0), "d") + 7

    .Range("D6:L" & 氏名最終行).Clear
    .Range(.Cells(7, 月末日), .Cells(氏名最終行, 月末日)).Copy .Range("G7")

        For i = 7 To 氏名最終行

            Set 最終公休日 = .Range(.Cells(i, 8), .Cells(i, 月末日)).Find(What:="公", LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious)

            If Not (最終公休日 Is Nothing) Then

            .Cells(i, 6).Value = 月末日 - 最終公休日.Column

                If .Cells(i, 7).Value = "B" Then
                    .Cells(i, 8).Value = "出"
                End If
            End If

        Next i

        If .Range("D4").Value < 12 Then
            .Range("D4").Value = .Range("D4") + 1
        Else
            .Range("D4").Value = 1
            .Range("C4").Value = .Range("C4") + 1
        End If
        .Range("L7:AL" & 氏名最終行).Clear
    End With
End Sub

皆様ありがとうございます。
 まだ添削して頂きたいものがありますので、もし良ければ宜しくお願い致します。

(なのれい) 2019/10/01(火) 17:03


■14
諸々踏まえると私ならこんな感じですかね。
 コンパイルエラーにならないことしかチェックしてないので雰囲気的なものと、インデント付けなどの参考にしてください。

    Sub さんぷるM()
        Dim 最終行 As Long, i As Long
        Dim 月末日 As Date
        Dim 最終公休日 As Range

        With Worksheets("作成シート")

            最終行 = .Cells(.Rows.Count, "D").End(xlUp).Row
            If 最終行 <= 6 Then
                MsgBox "データがありません"
                Exit Sub
            End If

            月末日 = DateSerial(.Range("C4"), .Range("D4") + 1, 0)

            '月前情報更新
            .Range("D7", .Cells(最終行, "L")).Clear
            .Range("H7", .Cells(最終行, "H").Offset(, Day(月末日) - 1)).Copy Range("G7")

            'なんかの処理
            For i = 7 To 最終行
                Set 最終公休日 = .Cells(i, "H").Resize(, Day(月末日)).Find(What:="公", LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlPrevious)
                If Not 最終公休日 Is Nothing Then
                    .Cells(i, 6).Value = Day(月末日) + 7 - 最終公休日.Column
                    If .Cells(i, 7).Value = "B" Then .Cells(i, 8).Value = "出"
                End If
            Next i

            '月次処理
            .Range("C4").Value = Year(月末日 + 1)
            .Range("D4").Value = Month(月末日 + 1)
            With .Range("H4")
                .Resize(, 30).ClearContents
                .NumberFormatLocal = "d"
                .Value = 月末日 + 1
                .AutoFill Destination:=.Resize(, Day(DateSerial(Year(月末日), Month(月末日) + 2, 0))), Type:=xlFillDefault
            End With

            '先月分情報クリア
            .Range("L7", .Cells(最終行, "AL")).Clear

        End With

    End Sub

(もこな2 ) 2019/10/01(火) 18:30


もこな2さんありがとうございます。

提案頂いたコードをしっかり理解して自分のコードに組んで行きたいと思います。
いつもありがとうございます。
(なのれい) 2019/10/01(火) 19:13


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.