[[20170202151355]] 『勤務表 当直5人ランダムしたいです、、助けてくax(SinNeo) ページの最後に飛ぶ

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

 

『勤務表 当直5人ランダムしたいです、、助けてください、、』(SinNeo)

勤務表を作成してますが、例え、何人かの専任職員と何人かの委員職員で毎日当直者を5人決めたいのですが、ランダムで下の条件通りの1ヶ月分か1年分作りたいのですが、一人一人の当直の回数をはじめに指定できればもっとうれしいのですが難しくて誰か教えてください。

条件
1、当直者は5人内、3人が電気、1人が水道、1人が空調として大学職員が3〜5人、委員職員が1〜2人でいたい

2、1日分で専任職員が3〜5人、委員職員が1〜3人(5人の場合がある)

3、1人分で当直6〜8回分でいたい

エクセルの学校の掲示板色々見て勉強したんですが、

シートのコード表

Private Sub Worksheet_Change(ByVal target As Range)

    If target.Count > 1 Then Exit Sub
    If target.Address <> "$A$1" Then Exit Sub
    If target.Value Like "*[!1-9]*" Then
        data = Val(StrConv(target, vbNarrow))
        Call macro(data, target)
    End If
 End Sub

標準モジュールもコード表

Sub macro(data, target)

    Dim rndvalue As Integer
    Dim i As Integer, Cnt As Integer, n As Integer, days As Integer
    Cnt = Application.WorksheetFunction.CountA(Range("a3:a24"))
    Range("b1:af1").Clear
    Range("b3:af24").Clear
    Randomize
    Application.EnableEvents = falsu
    Select Case data
        Case 1, 3, 5, 7, 8, 10, 12
            days = 31
        Case 4, 6, 9, 11
            days = 30
        Case Else
            If Year(Now) Mod 4 = 0 Then
                days = 29
            Else
                days = 28
            End If
    End Select
    For i = 1 To days
        Cells(1, i + 1) = i
    Next i
    For i = 1 To days
        rndvalue = (100 * Cnt * Rnd)
        n = (rndvalue Mod Cnt) + 1
        If Cells(n + 2, i) <> "電" Then
           Cells(n + 2, i + 1) = "電"
        If days <> i Then
                Cells(n + 2, i + 2) = "明"
            End If
        Else
            i = i - 1
        End If
    Next i
    For Each c In Range("b3:af24")
        If c.Value = "" Then
        rndvalue = (100 * Cnt * Rnd)
        n = (rndvalue Mod Cnt) + 1
        If Cells(n + 2, i) <> "空" Then
           Cells(n + 2, i + 1) = "空"
        If days <> c Then
                Cells(n + 2, i + 2) = "明"
        End If
    Next i
    Application.EnableEvents = True
End Sub

当直者が1人分(5人分も)エラーを出てしまって分からないです。
誰か助けてください。

< 使用 Excel:Excel2010、使用 OS:Windows7 >


変数宣言が無いものが多数ありますし、If文の始まりと終わりの関係が対になっていない等、自分でデバッグして直すべきところが多数有ります。また、シートのレイアウトが判らないので、コードが追えません。

例えば、A1セルに入力すると動作しますが、何を入力するのでしょう? 文字? 数字を除外しているようですが、0だけ許可しているのは何故?
入力OKならばmacroプロシジャに飛びますが、こっちは数字だけ判定? 許可した文字や0のCaseが無いという、矛盾。

もし判定が逆であり、数字だけOKとしたいならば、0を例外にしている意味が判りません。毎月10,20,30日を例外にしたいのでしょうか?

ステップ実行すれば、ご自分で矛盾に気づくものばかりですよ。
(???) 2017/02/02(木) 18:07


 >例え、何人かの専任職員と何人かの委員職員で毎日当直者を5人決めたいのですが、
 >条件 
 >1、当直者は5人内、3人が電気、1人が水道、1人が空調として大学職員が3〜5人、委員職員が1〜2人でいたい 
 >2、1日分で専任職員が3〜5人、委員職員が1〜3人(5人の場合がある) 
 >3、1人分で当直6〜8回分でいたい 

 この日本語、よく分からないです。

 1.専任職員と委員職員は、それぞれ全部で何人くらい居るのですか?

 2.大学職員と専任職員は同じ意味ですね?

 >当直者は5人内、3人が電気、1人が水道、1人が空調として大学職員が3〜5人、委員職員が1〜2人でいたい 
 3.具体的にどんな5人になったりするのか、2つほど例示して頂けませんか?

 4.「1人分で当直6〜8回分」とは、年間ベースですか、それとも月間ベースですか?

   (土日も当直ありですか?)

(半平太) 2017/02/02(木) 18:58


 半平太さんへ

 すみません。

 1、専任職員が15〜20人、委員職員は、5〜8人(異動や退職などによって変わります。)出来れば、数字を選べるようにしたい。

 2、すみません、同じです。

 3、例示するとA〜Hが専任大学、I〜Mが委員職員

 4種類があって

 電気=「電」 空調=「空」 水道=「水」 明け=「×」

 1月  1日  2日  3日  4日  5日  6日  7日  8日  9日  〜
      日   月   火   水   木   金   土   日   月

 専任職員
  A   電   ×       水   ×       電   ×

  B       空   ×       電   ×       電   ×

  C   空   ×   水   ×       電   ×   電   ×

  D           電   ×   電   ×   水   ×

  E       電   ×   空   ×       電   ×

  F   電   ×   電   ×       水   ×

  G       電   ×   電   ×   電   ×

  H           電   ×   空   ×       電   ×

 委員職員
  I   水   ×           水   ×   電   ×

  J       電   ×       電   ×   空   ×

  K   電   ×       電   ×   空   ×

  L           空   ×       電   ×   水   ×

  M       水   ×   電   ×           空   ×

 当直だけ表示

 1月  1日  2日  3日  4日  5日  6日  7日  8日  9日  〜
      日   月   火   水   木   金   土   日   月

 専任職員
  A   当   ×       当   ×       当   ×

  B       当   ×       当   ×       当   ×

  C   当   ×   当   ×       当   ×   当   ×

  D           当   ×   当   ×   当   ×

  E       当   ×   当   ×       当   ×

  F   当   ×   当   ×       当   ×

  G       当   ×   当   ×   当   ×

  H           当   ×   当   ×       当   ×

 委員職員
  I   当   ×           当   ×   当   ×

  J       当   ×       当   ×   当   ×

  K   当   ×       当   ×   当   ×

  L           当   ×       当   ×   当   ×

  M       当   ×   当   ×           当   ×

 予定が有る時、入力したセルはランダムしないようにしたい。予定=「予」

 1月  1日  2日  3日  4日  5日  6日  7日  8日  9日  〜
      日   月   火   水   木   金   土   日   月

 専任職員
  A   当   ×       当   ×       当   ×

  B       当   ×       当   ×       当   ×

  C   当   ×   予           当   ×   当   ×

  D           当   ×   当   ×   当   ×

  E       当   ×   当   ×       当   ×

  F   当   ×   当   ×       当   ×   予

  G       当   ×   当   ×   当   ×

  H           当   ×   当   ×       当   ×

 委員職員
  I   当   ×   当   ×   当   ×   当   ×

  J       当   ×       当   ×   当   ×

  K   当   ×       当   ×   当   ×

  L           当   ×       当   ×   当   ×

  M       当   ×   当   ×           当   ×

 例え、専任職員全員が忘年会(3日)する時、委員職員5人当直する。

 1月  1日  2日  3日  4日  5日  6日  7日  8日  9日  〜
      日   月   火   水   木   金   土   日   月

 専任職員
  A       当   ×       当   ×       当   ×

  B       当   ×       当   ×       当   ×

  C   当   ×       当   ×   当   ×   当   ×

  D   当   ×           当   ×   当   ×

  E       当   ×   当   ×   当   ×

  F   当   ×       当   ×       当   ×   

  G       当   ×   当   ×   当   ×

  H       当   ×   当   ×       当   ×

 委員職員
  I   当   ×   当   ×   当   ×       当   ×   

  J   当   ×   当   ×   当   ×   当   ×

  K           当   ×           当   ×

  L           当   ×       当   ×   当   ×

  M           当   ×       当   ×

 4、間違えました。1ヶ月分で1人当直6〜8回です。土日も当直ありです。 出来れば1人ずつ1人ずつバランス取るようにしたいです。

 お手数ですが、宜しくお願い致します。
(SinNeo) 2017/02/03(金) 14:16

 >予定が有る時、入力したセルはランダムしないようにしたい。予定=「予」 

 この予定とは、どのシート(名)に、どんなレイアウトで書かれているんですか?

(半平太) 2017/02/03(金) 14:56


 Worksheet_Changeのコードで、何を判定しようとしているのか、説明すべきです!
 A1セルに入力された文字が、1〜12(半角、または全角)の、どれかの数字かを判定したいなら
 次のような書き方もあります。
http://www.openreference.org/articles/view/582

 ですが、A1セルのデータは、データの入力規則で「1〜12(半角)」のリストから選ぶようにしておいて、
 Worksheet_Changeにはコードを記述せずに、例えば、シートにフォームコントロールのボタンを置いて、
 それをクリックすることで、macroのコードを走らせるなんて方法もありますよ。その方が簡単ですし。

 >SinNeo さんへ
 書込み文章の1行目とその後、改行毎ですが、文章の先頭に半角スペースを入れると、文字が小さくなります。
SinNeoさんの文章、先頭に半角スペースいれて、文字を小さくしておきました。
 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 
 Option Explicit '★変数の宣言を忘れない為に記述する

 Private Sub Worksheet_Change(ByVal target As Range)
    Dim x As String
    Dim Data As Integer
    Dim varArray() As Variant
    Dim varResult As Variant

    If target.Count > 1 Then Exit Sub '変更されたセルが1個を越えていたら、Exit Sub
    If target.Address <> "$A$1" Then Exit Sub 'targetがA1セル以外なら、Exit Sub
    x = target.Value
    If Not (IsNumeric(x) And x = Int(x) And x >= 1) Then Exit Sub '正の整数以外なら、Exit Sub

    Data = CInt(StrConv(x, vbNarrow)) 'xを半角にして、その後、数値型(Integer)に変換
    varArray = Array("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12")
    varResult = Filter(varArray, Data)
    If UBound(varResult) <> -1 Then
       MsgBox "入力されたのは、1〜12の数字のどれかです" & UBound(varResult)
    End If
 End Sub

(マリオ) 2017/02/03(金) 16:28


半平太さんへ

ありません。上のように表の中「予」と入力したい。もし無理なら別のシートでも問題ありません。
あと、出来れば、ある日、明けにしたい人が居てその日「×」して前の日が「当」(電・空・水もランダムしたい)と表示したい。

よろしくお願い致します。

(SinNeo) 2017/02/03(金) 17:51


 >SinNeo さん

 >例え、専任職員全員が忘年会(3日)する時、委員職員5人当直する。
 3日のとこに、当直空けを示す「×」がABEGHについてますが、CDFは空欄ですね。
 3日が忘年会なら、3日のところ、A〜H、すべてに「予」を入れておけばいいのでは?
 専任職員の欄すべてに「予」が入力されていたら、事務職員から当直の5人を選ぶようにする!

 ただ、問題なのは、2日に委員職員の2人(例えば、IとJ)が当直をしていた場合、
 3日の日は当直明けの「×」が入ります(IとJのところ)。
 すると、上記の例では、K,L,Mの3人しかいませんが、
 専任職員が忘年会で、誰も出れないので、3人の事務職員から、
 5人の当直を選出しないといけないということになりますね。
 ****************************************************************************
 >土日も当直ありです。 出来れば1人ずつ1人ずつバランス取るようにしたいです。
 土日の当直は、偏らないようにバランスをとりたいということですかね?
 ****************************************************************************
 >出来れば、ある日、明けにしたい人が居て
 ある日に「予」を入れるってことでいいんじゃないですか??????
 「予」が入っている前の日に「当」が入ったら、
 次の日の「予」を「×」(当直空けを表す×)で上書きしませんよね??
 ****************************************************************************
 まだ、整理できてませんが、こんな感じでしょうか?
 ・専任職員:20人、
 ・委員職員:  8人
 ・ただし、予定、異動、退職により当直できない場合あり。
 ・当直のない日は、1年を通して一日もない(祝日も当直をする)
 ・当直は、5人で行う。
 ・当直に決まった5人は、★特に決まりはなく、ランダムに
   電気担当が3人、空調担当が1人、水道担当が1人のどれかを行う。
 ・当直明けの次の日は、当直を行わない、次の日には「×」を入れ、
   次の日の当直候補から外す。
 ・(推測)当直は、専任職員から3人、委員職員から2人を選出する。
    ただし、例外として、忘年会の日は、委員職員から5人を選出する。
 ・予定があれば、シートに「予」をあらかじめ★手入力しておいて、
   その日の当直候補から外す。
 ・1ヶ月分あたり、1人の当直回数を6〜8回にしたい。
 ****************************************************************************

(マリオ) 2017/02/03(金) 18:04


 人数に増減があると言うのは、所謂、動的対応ですね。
 考えてみると、これは結構大変な話です。

 異動がある都度、作り替えなければなりません。

 向う1年のものを作っても、そんな先の予定が使えるとはとても思えないです。
 「過去1ヶ月、今月(進行中)、翌月予定」ぐらいの構成が妥当じゃないでしょうか。

 中には、途中で自分勝手に「予定を変えたい」なんてことを言う人も出て来るでしょうね。

 そんな異動の都度、ランダムに作り替えていたら、そのとばっちりで、
 それまで決まっていた他人様の予定も変更することになるので、
 文句続出となり、丸く治めるのは凄く大変そうです。

 私は自信がないので、ここで降ります。

(半平太) 2017/02/03(金) 22:48


マリオさんへ
そうです。こんな感じです。日本語不足ですみません。
お手数ですがよろしくお願い致します。
(SinNeo) 2017/02/03(金) 22:59

半平太さんへ

色々なことを言って迷惑を掛けてすみません。
「予定を変えたい」って言う人はいないです。大丈夫です。
ちゃんと締切日を決めてます。

専任職員が18人、委員職員が5人、設定でお願いします。異動はなしで大丈夫です。

参考として勉強したいので教えてください。

日本語不足ですみません。
お手数ですがよろしくお願い致します。
(SinNeo) 2017/02/03(金) 23:11


 1.サンプルブック作成プログラム

 (1)新規ブックの新規シートを「当直」に変更する。

 (2)当該シートモジュールにプログラム名「onlyOnce」を貼り付けて、実行する。

 ※実行が終わるとサンプルが出来上がり、「onlyOnce」は不要化しますので、
  そのプログラムは消し去ってください。

 Private Sub onlyOnce()
      Rem 結合状態を処理
      Range("E1:H1").Merge
      Range("J1:M1").Merge

      Rem 生データのセルをまとめて処理
      Range("A1").Value = "計算開始日"
      Range("B1,Q2").Value = 42767
      Range("E1").Value = "過去以前実績"
      Range("J1").Value = "計算開始日前実績"
      Range("A2").Value = "氏名"
      Range("B2").Value = "所属"
      Range("C2").Value = "途中開始日"
      Range("D2").Value = "途中終了日"
      Range("E2,J2").Value = "回数"
      Range("F2,K2").Value = "空調"
      Range("G2,L2").Value = "水道"
      Range("H2,M2").Value = "電気"
      Range("R2,D5").Value = 42768
      Range("S2").Value = 42769
      Range("T2,D4").Value = 42770
      Range("U2,C3").Value = 42771
      Range("V2").Value = 42772
      Range("W2").Value = 42773
      Range("X2").Value = 42774
      Range("Y2").Value = 42775
      Range("Z2").Value = 42776
      Range("AA2").Value = 42777
      Range("AB2").Value = 42778
      Range("AC2").Value = 42779
      Range("AD2").Value = 42780
      Range("AE2").Value = 42781
      Range("AF2").Value = 42782
      Range("AG2").Value = 42783
      Range("AH2").Value = 42784
      Range("AI2").Value = 42785
      Range("AJ2").Value = 42786
      Range("AK2").Value = 42787
      Range("AL2").Value = 42788
      Range("AM2").Value = 42789
      Range("A3:A20,A23:A27").Value = "各人名"
      Range("B3:B20").Value = "専任"
      Range("E3:H20,E21:E22,E23:H27").Value = 0
      Range("B23:B27").Value = "委員"

      Rem 数式セルをまとめて処理
      Range("C1").FormulaR1C1Local = "=MATCH(RC[-1],R[1],0)"
      Range("D1").FormulaR1C1Local = "=MATCH(8^8,R[1])"
      Range("J3:J27").FormulaR1C1Local = "=SUM(RC[1]:RC[3])"
      Range("K3:M27").FormulaR1C1Local = "=COUNTIFS(R2C17:R2C423,""<""&R1C2,RC17:RC423,LEFT(R2C)&""*"")"

      Rem 標準外書式セルをまとめて処理
      Range("B1").NumberFormatLocal = "yyyy/m/d"
      Range("C1").NumberFormatLocal = "0""列から"""
      Range("D1").NumberFormatLocal = "0""列まで"""
      Range("Q1:AM1").NumberFormatLocal = "m"
      Range("Q2:AM2").NumberFormatLocal = "d"
      Range("A3:A27").NumberFormatLocal = "@"
      Range("C3,D4:D5").NumberFormatLocal = "m""月""d""日"""

     Rows("2:2").Orientation = xlVertical
     Columns("A:BC").EntireColumn.AutoFit
 End Sub

 2.本番プログラム

 (1)「当直」シートモジュールへ(さっき「onlyOnce」を貼り付けた所と同じです)

 Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)

     If Target.Address <> "$B$1" Then
         Exit Sub
     ElseIf IsEmpty(Target.Value) Then
         Exit Sub
     ElseIf MsgBox("再計算を行います。" & vbLf & vbLf & _
         Me.Range("B1") & "以降のデータは全て書き換わります" & vbLf & vbLf & _
         "但し、右の2種はそのまま→「×-」「予」", vbYesNo) = vbNo Then
         Exit Sub
     Else
         Cancel = True
         Call Main("Dummy")
     End If
 End Sub

 ’2(1) ここまで −−−−−−−−−−−−−−−−−−−−−−−−−−

 (2)標準モジュールへ

 Type Duty
     TD名前 As String
     TD所属 As String
     TD開始 As Variant
     TD終了 As Variant
     TD当直回数 As Long  '途中加入が居るので、
                         '必ずしも合計回数は内訳合計とは合致しない
     TD当直空 As Long
     TD当直水 As Long
     TD当直電 As Long

     TDレベル As Long    '翌明希望により必須(0),通常(1),不可(3,4,5,6,7,8,9)
     TD行番 As Long
     TD結果 As Variant
 End Type

 Const numToPickUp As Long = 5

 Sub Main(ByVal Dummy As String)
     Dim Duties() As Duty
     Dim rowNObyPriority As Long

     Dim baseDate As Date
     Dim startCol As Long, endCol As Long

     Dim Wsh As Worksheet

     Dim lastNum As Long

     Dim orderToProc

     Dim NN As Long
     Dim rowNum As Long
     Dim colToProc As Long

     Dim Found As Boolean

     Dim 比率専任 As Long, 比率委員 As Long
     Dim 上限専任 As Long, 上限委員 As Long

     Dim 専委内訳(1 To 3) As Long '専任(1),委員(2),合計(3)
     Dim 前日当直  As Variant     '前日「当直」なら、本日「×」にする
     Dim 翌日の予定 As Variant    '翌日「×」なら本日は当直必須(但し前日が当直は不可)
                                  '「予-」なら当直不可
     Dim 翌翌明け希望 As Variant  '翌翌日「明」なら、本日は当直不可

     Dim AryToShow()
     Dim Role乱数(1 To numToPickUp), RoleOrder
     Dim Five配列番(1 To numToPickUp)
     Dim 電含有率 As Long

     Set Wsh = Sheets("当直")            'シート名は「当直」とする

     startCol = Wsh.Range("C1").Value    '再計算開始列番
     endCol = Wsh.Range("D1").Value      '再計算終了列番

     lastNum = Wsh.Cells(500, "A").End(xlUp).Row - 2 'データ行数を把握

     ReDim Duties(1 To lastNum)            '当直候補者の配列
     ReDim AryToShow(1 To lastNum, 1 To 1) '各日の当直結果データ

 '各候補の計算開始日以前の実績データをセットする
     For rowNum = 3 To lastNum + 2
         With Duties(rowNum - 2)
             .TD名前 = Wsh.Cells(rowNum, 1).Value
             .TD所属 = Wsh.Cells(rowNum, 2).Value
             .TD開始 = Wsh.Cells(rowNum, 3).Value
             .TD終了 = Wsh.Cells(rowNum, 4).Value

             .TD当直回数 = Wsh.Cells(rowNum, 5) + Wsh.Cells(rowNum, 10)
             .TD当直空 = Wsh.Cells(rowNum, 6) + Wsh.Cells(rowNum, 11)
             .TD当直水 = Wsh.Cells(rowNum, 7) + Wsh.Cells(rowNum, 12)
             .TD当直電 = Wsh.Cells(rowNum, 8) + Wsh.Cells(rowNum, 13)

             .TD行番 = rowNum
         End With
     Next rowNum

     Randomize

 '日付の順(=列毎)に各人の基本データをセットする
     For colToProc = startCol To endCol

         baseDate = Wsh.Cells(2, colToProc).Value '計算対象の日付

         For NN = 1 To lastNum

             With Duties(NN)
                 .TDレベル = 1 '選択レベルの初期化

                 翌翌明け希望 = Wsh.Cells(.TD行番, colToProc + 2)  '→9
                 翌日の予定 = Wsh.Cells(.TD行番, colToProc + 1)    '→0
                 前日当直 = Wsh.Cells(.TD行番, colToProc - 1)      '→9

             '「予定」関係
                 If Wsh.Cells(.TD行番, colToProc) = "予" Then  '手入力
                      .TDレベル = 7             '予定なので対象外
                 ElseIf Wsh.Cells(.TD行番, colToProc) = "×-" Then  '手入力の「×-」
                     .TDレベル = 6
                 End If

              '「翌翌明け希望」関係
                 If 翌翌明け希望 = "×-" Then
                          .TDレベル = 6          '翌翌明け希望なので選択不可
                 End If

               '「翌明け希望」関係
                 If "×-" = 翌日の予定 Then
                          .TDレベル = 0          '翌明け希望なので選択必須
                 End If

                '翌日が「予定」の場合
                 If 翌日の予定 = "予" Then
                          .TDレベル = 6          '翌明けが予定なので選択不可
                 End If

             '「明け」関係
                 If Len(前日当直) Then
                     If InStr("空水電 ", 前日当直) Then
                          .TDレベル = 8          '明けなので選択不可
                     End If
                 End If

             '開始日関係
                 If baseDate < .TD開始 Then
                      .TDレベル = 9             '開始前なので選択不可
                 End If

             '終了日関係
                 If .TD終了 <> Empty Then '記入ありの場合
                     If .TD終了 <= baseDate Then '終了日以後
                         .TDレベル = 9
                     End If
                 End If

                 If Duties(NN).TDレベル < 3 Then '当直可能数の統計を取る
                     If .TD所属 = "専任" Then
                         比率専任 = 比率専任 + 1
                     ElseIf .TD所属 = "委員" Then
                         比率委員 = 比率委員 + 1
                     End If
                 End If
             End With

         Next NN

         '専任/委員条件算出
         上限専任 = Application.RoundUp(numToPickUp * 比率専任 / (比率専任 + 比率委員), 0)
         上限委員 = numToPickUp - 上限専任 + 1

         orderToProc = getOrder(Duties, lastNum) '優先順に並んだ候補者の背番号(配列位置)を取得する

     '5人に絞る
         For NN = 1 To lastNum
             rowNObyPriority = orderToProc(NN)     '優先順に背番号を取出す

             If Duties(rowNObyPriority).TDレベル < 3 Then '選択対象はレベル2以下
                 Found = False '初期値セット

                 Select Case Duties(rowNObyPriority).TD所属
                     Case "専任"
                         If 専委内訳(1) < 上限専任 Then
                             Found = True
                             専委内訳(1) = 専委内訳(1) + 1
                         End If

                     Case "委員"
                         If 専委内訳(2) < 上限委員 Then
                             Found = True
                             専委内訳(2) = 専委内訳(2) + 1
                         End If
                 End Select

                 If Found Then

                     専委内訳(3) = 専委内訳(3) + 1           '(3)はピックアップ合計

                     Five配列番(専委内訳(3)) = rowNObyPriority '合計位置(12,3,4,5)にセット

                     If 専委内訳(3) >= numToPickUp Then
                         Exit For
                     End If
                 End If

             End If
         Next NN

     '5人の役割を決定する(各自の当直種類の含有比率で並べ替え)
         For NN = 1 To numToPickUp
             With Duties(Five配列番(NN))
                 If .TD当直回数 = 0 Then
                     電含有率 = 0
                 Else
                     電含有率 = Application.RoundUp(.TD当直電 * 100 / .TD当直回数, 0)
                 End If

                 Role乱数(NN) = 電含有率 * 10000000 + _
                            .TD当直水 * 100000 + _
                            .TD当直空 * 1000 + NN
             End With
         Next NN

         With Application
             RoleOrder = .Match(.Small(Role乱数, Array(1, 2, 3, 4, 5)), Role乱数, 0)
             RoleOrder = .Lookup(RoleOrder, Array(1, 2, 3, 4, 5), Five配列番)
         End With

     '表示文字をセットする
         ReDim AryToShow(1 To lastNum, 1 To 1)
         Dim preRole, role, pos As Variant, errNum, ckPerf
         Erase 専委内訳

         For NN = 1 To lastNum

             Duties(NN).TD結果 = Empty '初期化

             'セルに記入済み役割があるかチェック
             role = Wsh.Cells(Duties(NN).TD行番, colToProc).Value

             If role <> "×-" And role <> "予" Then     '手入力文字でなければ

                 On Error Resume Next
                     With Application
                         pos = .Max(1, .Match(NN, RoleOrder, 0) - 2)
                     End With
                     errNum = Err.Number
                 On Error GoTo 0

                 If errNum = 0 Then
                    Duties(NN).TD結果 = Application.Choose(pos, "電", "水", "空")
                 Else
                     preRole = Wsh.Cells(Duties(NN).TD行番, colToProc - 1)
                     If Not IsEmpty(preRole) Then
                          If InStr("空水電", Wsh.Cells(Duties(NN).TD行番, colToProc - 1)) Then
                             Duties(NN).TD結果 = "×"
                          End If
                     End If
                 End If
             Else
                 Duties(NN).TD結果 = role
             End If

             Select Case Duties(NN).TD結果
                 Case "空": Duties(NN).TD当直空 = Duties(NN).TD当直空 + 1: Duties(NN).TD当直回数 = Duties(NN).TD当直回数 + 1
                 Case "水": Duties(NN).TD当直水 = Duties(NN).TD当直水 + 1: Duties(NN).TD当直回数 = Duties(NN).TD当直回数 + 1
                 Case "電": Duties(NN).TD当直電 = Duties(NN).TD当直電 + 1: Duties(NN).TD当直回数 = Duties(NN).TD当直回数 + 1
             End Select

         Next NN

         For NN = 1 To lastNum
             AryToShow(NN, 1) = Duties(NN).TD結果
         Next NN

     '一列表示
         Wsh.Cells(3, colToProc).Resize(lastNum).Value = AryToShow

     '空1、水1、電3人居るか再チェック
         ckPerf = Application.CountIf(Wsh.Cells(3, colToProc).Resize(lastNum), Array("空", "水", "電"))

         If ckPerf(1) <> 1 Or ckPerf(2) <> 1 Or ckPerf(3) <> 3 Then
             MsgBox "所定の当直数になっておりません。処理中止 m(__)m"
             Stop
         End If
     Next colToProc
 End Sub

 Function getOrder(Duties() As Duty, ByVal lastNum As Long)
     Dim NN As Long
     Dim 乱数rand()

     ReDim 乱数(1 To lastNum)

     For NN = 1 To lastNum
         乱数(NN) = Duties(NN).TDレベル * 10000 + Duties(NN).TD当直回数 * 10 + Rnd
     Next NN

     With Application
         getOrder = .Transpose(.Match(.Small(乱数, Evaluate("ROW(1:" & lastNum & ")")), 乱数, 0))
     End With

 End Function

 ’2(2)ここまでーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

 3.使い方 
 (1)「各人名」を本人名にする
 (2) Q2セルに当直表の最初の日付(シリアル値)を入力し、その右方向にドラッグして、作りたい表の最終日付に達するまで日付連番を入れる。
 (3) B1セルに計算を始めたい日付(シリアル値)を入れる
 (4) 作表したいときは、そのB1セルを右クリックして「OK」ボタンをクリックする。(再計算でも同じ方法)

 4.細かい使い方
 (1)休み明けにしたい人が居る場合は、該当日に「×-」を入れる。
   後ろのハイフン「-」をお忘れなく。プログラムで出力する単発の「×」と区別する為です。

 (2)「予定」にしたい人が居る場合は、該当日に「予」を入れる。

 (3)途中で終わる人は、D列の該当行にその終了日を入れる(シリアル値)

 (4)途中で参加する人は、C列の該当行にその開始日を入れる(シリアル値)
   途中で参加する人は実績が0ですから、何も手当しないと高い確率で当直に当たります。
   なので、標準の人の回数を参考にして、E列(回数)を強制的に水増しするといいです。
   当直種類の内訳も強制水増ししたら、もっと自然になりますが、それは任意です。

 5.再計算
 上記3の(4)と同じ。(B1セルに再計算したい日付を入れてから実行)

 ※誰かの予定が急に変わったとき、再計算を行うことになりますが、
 その予定変更日が、当日から極めて近いと、再計算によって、
 他人様の予定も急に変わってしまい、不満が出る恐れがあります。

 なので、取り敢えず、1週間分くらいは手修正で行い、
 影響を受ける人(多分1人で済む)に了解を取る方が穏便だと思います。

 ・・・で、再計算は当日から1週間くらい先の日付をB1セルに
 入力して実行すればいいかなと・・・余計なお世話かも知れませんが。

(半平太) 2017/02/05(日) 13:24


半平太さんへ

ありがとうございます!!
勉強になります!

すみません。質問があります。
休日を入力する時は、

'「休日」関係

                 If Wsh.Cells(.TD行番, colToProc) = "休" Then  '手入力
                      .TDレベル = 7             '休日なので対象外
                 ElseIf Wsh.Cells(.TD行番, colToProc) = "×-" Then  '手入力の「×-」

こんな感じですか?実行して大丈夫ですけどどうでしょうか


Type Duty
     TD名前 As String
     TD所属 As String
     TD開始 As Variant
     TD終了 As Variant
     TD当直回数 As Long  '途中加入が居るので、
                         '必ずしも合計回数は内訳合計とは合致しない
     TD当直空 As Long
     TD当直水 As Long
     TD当直電 As Long
     TDレベル As Long    '翌明希望により必須(0),通常(1),不可(3,4,5,6,7,8,9)
     TD行番 As Long
     TD結果 As Variant
 End Type
 Const numToPickUp As Long = 5
 Sub Main(ByVal Dummy As String)
     Dim Duties() As Duty
     Dim rowNObyPriority As Long
     Dim baseDate As Date
     Dim startCol As Long, endCol As Long
     Dim Wsh As Worksheet
     Dim lastNum As Long
     Dim orderToProc
     Dim NN As Long
     Dim rowNum As Long
     Dim colToProc As Long
     Dim Found As Boolean
     Dim 比率専任 As Long, 比率委員 As Long
     Dim 上限専任 As Long, 上限委員 As Long
     Dim 専委内訳(1 To 3) As Long '専任(1),委員(2),合計(3)
     Dim 前日当直  As Variant     '前日「当直」なら、本日「×」にする
     Dim 翌日の予定 As Variant    '翌日「×」なら本日は当直必須(但し前日が当直は不可)
                                  '「予-」なら当直不可
     Dim 翌翌明け希望 As Variant  '翌翌日「明」なら、本日は当直不可
     Dim AryToShow()
     Dim Role乱数(1 To numToPickUp), RoleOrder
     Dim Five配列番(1 To numToPickUp)
     Dim 電含有率 As Long
     Set Wsh = Sheets("当直")            'シート名は「当直」とする
     startCol = Wsh.Range("C1").Value    '再計算開始列番
     endCol = Wsh.Range("D1").Value      '再計算終了列番
     lastNum = Wsh.Cells(500, "A").End(xlUp).Row - 2 'データ行数を把握
     ReDim Duties(1 To lastNum)            '当直候補者の配列
     ReDim AryToShow(1 To lastNum, 1 To 1) '各日の当直結果データ
 '各候補の計算開始日以前の実績データをセットする
     For rowNum = 3 To lastNum + 2
         With Duties(rowNum - 2)
             .TD名前 = Wsh.Cells(rowNum, 1).Value
             .TD所属 = Wsh.Cells(rowNum, 2).Value
             .TD開始 = Wsh.Cells(rowNum, 3).Value
             .TD終了 = Wsh.Cells(rowNum, 4).Value
             .TD当直回数 = Wsh.Cells(rowNum, 5) + Wsh.Cells(rowNum, 10)
             .TD当直空 = Wsh.Cells(rowNum, 6) + Wsh.Cells(rowNum, 11)
             .TD当直水 = Wsh.Cells(rowNum, 7) + Wsh.Cells(rowNum, 12)
             .TD当直電 = Wsh.Cells(rowNum, 8) + Wsh.Cells(rowNum, 13)
             .TD行番 = rowNum
         End With
     Next rowNum
     Randomize
 '日付の順(=列毎)に各人の基本データをセットする
     For colToProc = startCol To endCol
         baseDate = Wsh.Cells(2, colToProc).Value '計算対象の日付
         For NN = 1 To lastNum
             With Duties(NN)
                 .TDレベル = 1 '選択レベルの初期化
                 翌翌明け希望 = Wsh.Cells(.TD行番, colToProc + 2)  '→9
                 翌日の予定 = Wsh.Cells(.TD行番, colToProc + 1)    '→0
                 前日当直 = Wsh.Cells(.TD行番, colToProc - 1)      '→9
             '「予定」関係
                 If Wsh.Cells(.TD行番, colToProc) = "予" Then  '手入力
                      .TDレベル = 7             '予定なので対象外
                 ElseIf Wsh.Cells(.TD行番, colToProc) = "×-" Then  '手入力の「×-」
                     .TDレベル = 6
                 End If
             '「休日」関係
                 If Wsh.Cells(.TD行番, colToProc) = "休" Then  '手入力
                      .TDレベル = 7             '休日なので対象外
                 ElseIf Wsh.Cells(.TD行番, colToProc) = "×-" Then  '手入力の「×-」
                     .TDレベル = 6
                 End If
              '「翌翌明け希望」関係
                 If 翌翌明け希望 = "×-" Then
                          .TDレベル = 6          '翌翌明け希望なので選択不可
                 End If
               '「翌明け希望」関係
                 If "×-" = 翌日の予定 Then
                          .TDレベル = 0          '翌明け希望なので選択必須
                 End If
                '翌日が「予定」の場合
                 If 翌日の予定 = "予" Then
                          .TDレベル = 6          '翌明けが予定なので選択不可
                 End If
             '「明け」関係
                 If Len(前日当直) Then
                     If InStr("空水電 ", 前日当直) Then
                          .TDレベル = 8          '明けなので選択不可
                     End If
                 End If
             '開始日関係
                 If baseDate < .TD開始 Then
                      .TDレベル = 9             '開始前なので選択不可
                 End If
             '終了日関係
                 If .TD終了 <> Empty Then '記入ありの場合
                     If .TD終了 <= baseDate Then '終了日以後
                         .TDレベル = 9
                     End If
                 End If
                 If Duties(NN).TDレベル < 3 Then '当直可能数の統計を取る
                     If .TD所属 = "専任" Then
                         比率専任 = 比率専任 + 1
                     ElseIf .TD所属 = "委員" Then
                         比率委員 = 比率委員 + 1
                     End If
                 End If
             End With
         Next NN
         '専任/委員条件算出
         上限専任 = Application.RoundUp(numToPickUp * 比率専任 / (比率専任 + 比率委員), 0)
         上限委員 = numToPickUp - 上限専任 + 1
         orderToProc = getOrder(Duties, lastNum) '優先順に並んだ候補者の背番号(配列位置)を取得する
     '5人に絞る
         For NN = 1 To lastNum
             rowNObyPriority = orderToProc(NN)     '優先順に背番号を取出す
             If Duties(rowNObyPriority).TDレベル < 3 Then '選択対象はレベル2以下
                 Found = False '初期値セット
                 Select Case Duties(rowNObyPriority).TD所属
                     Case "専任"
                         If 専委内訳(1) < 上限専任 Then
                             Found = True
                             専委内訳(1) = 専委内訳(1) + 1
                         End If
                     Case "委員"
                         If 専委内訳(2) < 上限委員 Then
                             Found = True
                             専委内訳(2) = 専委内訳(2) + 1
                         End If
                 End Select
                 If Found Then
                     専委内訳(3) = 専委内訳(3) + 1           '(3)はピックアップ合計
                     Five配列番(専委内訳(3)) = rowNObyPriority '合計位置(12,3,4,5)にセット
                     If 専委内訳(3) >= numToPickUp Then
                         Exit For
                     End If
                 End If
             End If
         Next NN
     '5人の役割を決定する(各自の当直種類の含有比率で並べ替え)
         For NN = 1 To numToPickUp
             With Duties(Five配列番(NN))
                 If .TD当直回数 = 0 Then
                     電含有率 = 0
                 Else
                     電含有率 = Application.RoundUp(.TD当直電 * 100 / .TD当直回数, 0)
                 End If
                 Role乱数(NN) = 電含有率 * 10000000 + _
                            .TD当直水 * 100000 + _
                            .TD当直空 * 1000 + NN
             End With
         Next NN
         With Application
             RoleOrder = .Match(.Small(Role乱数, Array(1, 2, 3, 4, 5)), Role乱数, 0)
             RoleOrder = .Lookup(RoleOrder, Array(1, 2, 3, 4, 5), Five配列番)
         End With
     '表示文字をセットする
         ReDim AryToShow(1 To lastNum, 1 To 1)
         Dim preRole, role, pos As Variant, errNum, ckPerf
         Erase 専委内訳
         For NN = 1 To lastNum
             Duties(NN).TD結果 = Empty '初期化
             'セルに記入済み役割があるかチェック
             role = Wsh.Cells(Duties(NN).TD行番, colToProc).Value
             If role <> "×-" And role <> "予" And role <> "休" And role <> "週" And role <> "日" And role <> "有" And role <> "出" Then     '手入力文字でなければ
                 On Error Resume Next
                     With Application
                         pos = .Max(1, .Match(NN, RoleOrder, 0) - 2)
                     End With
                     errNum = Err.Number
                 On Error GoTo 0
                 If errNum = 0 Then
                    Duties(NN).TD結果 = Application.Choose(pos, "電", "水", "空")
                 Else
                     preRole = Wsh.Cells(Duties(NN).TD行番, colToProc - 1)
                     If Not IsEmpty(preRole) Then
                          If InStr("空水電", Wsh.Cells(Duties(NN).TD行番, colToProc - 1)) Then
                             Duties(NN).TD結果 = "×"
                          End If
                     End If
                 End If
             Else
                 Duties(NN).TD結果 = role
             End If
             Select Case Duties(NN).TD結果
                 Case "空": Duties(NN).TD当直空 = Duties(NN).TD当直空 + 1: Duties(NN).TD当直回数 = Duties(NN).TD当直回数 + 1
                 Case "水": Duties(NN).TD当直水 = Duties(NN).TD当直水 + 1: Duties(NN).TD当直回数 = Duties(NN).TD当直回数 + 1
                 Case "電": Duties(NN).TD当直電 = Duties(NN).TD当直電 + 1: Duties(NN).TD当直回数 = Duties(NN).TD当直回数 + 1
             End Select
         Next NN
         For NN = 1 To lastNum
             AryToShow(NN, 1) = Duties(NN).TD結果
         Next NN
     '一列表示
         Wsh.Cells(3, colToProc).Resize(lastNum).Value = AryToShow
     '空1、水1、電3人居るか再チェック
         ckPerf = Application.CountIf(Wsh.Cells(3, colToProc).Resize(lastNum), Array("空", "水", "電"))
         If ckPerf(1) <> 1 Or ckPerf(2) <> 1 Or ckPerf(3) <> 3 Then
             MsgBox "所定の当直数になっておりません。処理中止 m(__)m"
             Stop
         End If
     Next colToProc
 End Sub
 Function getOrder(Duties() As Duty, ByVal lastNum As Long)
     Dim NN As Long
     Dim 乱数rand()
     ReDim 乱数(1 To lastNum)
     For NN = 1 To lastNum
         乱数(NN) = Duties(NN).TDレベル * 10000 + Duties(NN).TD当直回数 * 10 + Rnd
     Next NN
     With Application
         getOrder = .Transpose(.Match(.Small(乱数, Evaluate("ROW(1:" & lastNum & ")")), 乱数, 0))
     End With
 End Function

(SinNeo) 2017/02/06(月) 15:24

 「予定」とは休みのことかと思っていたのですが、別ですか。

 想定外の手入力データなので、再計算で消えてしまうと思いますけど?

 消させないためには、ここも直さないとまずいと思います。

   If role <> "×-" And role <> "予" And role <> "休" Then    '手入力文字でなければ
                   ~~~~~~~~↑~~~~~~~
                      追加

  ※「プログラムで出す文字なら消す」と言うロジックにすればよかったと反省。

 それ以外に影響が出るかどうかは分かりません。

 >実行して大丈夫ですけどどうでしょうか

 本当に大丈夫なんですかね?(問題なさそうな気もしますが、ちょっと自信ないです)
 同じ様なテストをもう一度やる気は起きないので、そちらでテストして洗い出してください。

(半平太) 2017/02/06(月) 16:25


半平太さんへ

ありがとうございます!!
テストやってみました。問題ありません!!

すみません、お願いがあります。

出来ない部分がありまして
確かに、当直は、専任職員から3人、委員職員から2人を選出しますけど
例外として、忘年会の日は、委員職員から5人を選出したいですけど入力しても委員職員が4人を選出してしまう。
どうすればいいでしょうか?

下記の通り追加出来ますか?

専任職員と委員職員
当直は、専任職員から3人、委員職員から2人を選出しますけど
この数字変更出来ますか?(当直は、5人設定として)

土日祝日休みの仕事がありまして、
金曜日当直→1人1回(1ヶ月分)
土曜日当直→1人1回(1ヶ月分)
日曜日当直→1人1回(1ヶ月分)

下記のとおり、自動的に計算したいです。
1、当直回数
2、土・金曜日当直した人は、半休となり0.5日とする。
3、半休二つがあったら、1日休みとする。

文字変更
電気→当直

何度も何度も言って本当にすみません。
出来るだけでいいです。

お手数ですが、よろしくお願いします。
(SinNeo) 2017/02/06(月) 16:46


 > 確かに、当直は、専任職員から3人、委員職員から2人を選出しますけど 

 これは私のミスです。役割変数の初期化をしていなかったです。下記の通り2行挿入してください。  m(__)m

         baseDate = Wsh.Cells(2, colToProc).Value '計算対象の日付

         比率専任 = 0  '初期化 '←ここに挿入         
         比率委員 = 0  '初期化 '←ここに挿入

         For NN = 1 To lastNum

 この初期化をして置けば、いつもは専任が4人くらい、委員は2人くらいが上限になります。

 専任が忘年会の時、全員を「予」にしておけば、専任は0人になって問題ないと思っていたのですが、
 よく考えたら、忘年会の当日だけについて考えても、旨い事いかなかったですね。

 忘年会の前日に委員が当番になっていたとしたら、その人は忘年会の日は「×」であって、
 もう一度続けて当直させる訳には行かない(と理解しております)。

 だけど、候補者は委員5人しかいない。これは理論的破たんです。

 そうなると、2日位前から当直の調整が必要と思うのですが、私の勘違いもあるかも知れませんので
 ちょっとその(理想図)を書いて貰えませんか? (下図のAF列とAG列を埋めて貰えませんか?)

 <当直>       この列
          ↓  ↓
  行  _AD_  _AE_  _AF_  _AG_  _AH_
   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         電    ×          電  

 >下記の通り追加出来ますか? 

 申訳ないですが、完全な後出し条件ですので、ご期待に沿えません。m(__)m

(半平太) 2017/02/06(月) 18:38


 >半平太さん、SinNeoさん
 ついて、いけてないです。下地のファイルを作成したのでアップします。参考にしてください。未完成です。
http://d.kuku.lu/2aca665de3
 ※忘年会の日は、委員職員だけで当直を行う処理は、一番はじめに処理した方がいいですね。

 シート構成(未完成です!)
 ・横表・縦表・休み・祝日・1〜23
 --------------------------------
 横表シートの「年、月のスピンボタン」を押すと、
 「1〜23シート」の休みの日付を読み込んで、該当の箇所に「予」の文字を入れます。
 また、「休みシート」の休みの日付を読み込んで、該当の箇所に「■」の文字を入れます。
 --------------------------------
 横表シートの「作成ボタン」を押すと、
 専任職員がすべて「予」の日付の列番号をmsgboxで表示します。
 --------------------------------
 横表シートの「表示ボタン」を押すと、
 全シートを表示します。
 --------------------------------
 横表シートの「非表示ボタン」を押すと、
 「横表シートと縦表シート」以外のシートを非表示にします。

(マリオ) 2017/02/06(月) 22:46


半平太さん

出来ました!!

完全な後出し条件ですか、そうなんですか、、
迷惑をかけて申し訳がないです、、ありがとうございます!!
(SinNeo) 2017/02/07(火) 12:17


マリオさん
すごいですね!!分かりやすいです!!
すみません。最低ですみません。尊敬します!!

当直はどうやって入ればいいんですか?

この下記の通り追加出来ますか?

1、当直の名前(電気・空調・水道)変更したい

2、例外としてある人に電気当直だけ(専門の為)設定したい、空調当直除いてその以外当直設定したい(資格をもってる為)

3、土日祝日休みの仕事がありまして、

  金曜日当直→1人0〜1回(1ヶ月分) 
  土曜日当直→1人0〜1回(1ヶ月分) 
  日曜日当直→1人0〜1回(1ヶ月分) 
  ランダムしたい

4、出来れば、「予」でも大丈夫ですが
  例外としてある日、日勤したい人、出張する人、有休したい人居まして、追加したい。

  日勤=「日」出張=「出」有休=「有」

5、もし出来るなら、自動計算したい
  ・当直回数

  ・金曜日と土曜日当直した人は、半休となり0.5日とする。 
  ・半休二つがあったら、1日休みとする。

お手数ですがよろしくお願いします、迷惑をかけてすみません。参考になりますしもっと勉強したいです。何かあったら言います。
(SinNeo ) 2017/02/07(火) 12:33


 >SinNeoさん
 誠意がまったく感じられません。さようなら。
(マリオ) 2017/02/07(火) 14:30

マリオさんへ

誠意がなく調子を乗って言って申し訳がありません。
本当に色々教えてくれてありがとうございます。

頑張って自分で考えて作ります。
(SinNeo ) 2017/02/07(火) 16:15


マリオさんへ

本当に反省してます。本当にすみません。
(SinNeo) 2017/02/07(火) 21:24


マリオさんへ

何度も何度も言ってすみません、、、

作成してくれたファイル
とても分かりやすくて便利です。

すみませんが、、無視してるのは承知しております。
質問が有ります。

シート「縦表」ってちょっとわかりますが、当直はどうやって入力すればいいでしょうか、、
(SinNeo ) 2017/02/08(水) 15:23


SinNeoさんへ

まだ見ていらしたら、続きをやりませんか

(トラ) 2017/02/14(火) 08:39


トラ様へ

ありがとうございます。
すみませんが宜しくお願いします。
(SinNeo) 2017/02/15(水) 13:06


SinNeoさんへ

シフトスケジュールの問題は、プログラムコードを作る前に
条件を詰めることが、非常に重要です。
これが十分でないと(後出し)になりまり、途中で投げ出すことになります。。

これから記することは、今までのやり取りをまとめた物です。

1
当直のない日は、1年を通して一日もない (祝日も当直をする)
当直は、午前八時から翌日の午前八時まで
連続当直は無 連続当直・・・当直明けからすぐに次の当直に入ること
当直は、5人で行う
電気担当が3人、空調担当が1人、水道担当が1人で行う
シフトスケジュール表は来月まで作成する
同姓同名は避ける、片方を平仮名にするとかする
半日当直とかは無い・・実際に有ったとしてもこのスケジュール表上では扱えない

2
専任職員が15〜20人
専任職員は、5〜8人
専任職員、専任職員の順に名簿に記入
当直は、5人で行う 専任職員 - 3人,委員職員 - 1人, 当直回数の少ない人 - 1人
専任、委員で当直回数を区別しない
途中で参加する人は、E列の該当行にその開始日を入れる (シリアル値)
途中で終わる人は、F列の該当行にその終了日を入れる (シリアル値)

プログラムでのスケジュール
3
休日希望を入力できる、休日直前日の当直は不可
当直希望を入力できる・・・連続当直は無
例外を除いて一日あたりの(休日希望+当直希望)は人数の1/4まで(四捨五入)とする
(専任職員が15人、委員職員5人だとしたら4人まで)
前々月、前月、当月での当直回数の平均化
金土日の当直の平均化・・・祝日の扱い
電気担当、空調担当人、水道担当の平均化
電気担当・・・資格を持っていれば電気担当にする
人物の組み合わせは(同じメンバーになっても良い・・・易しい)(同じ人となるべく組まない・・・非常に難しい)
休日希望,当直希望が無ければ、当直,休日(3〜2),当直,休日(3〜2),当直,休日(3〜2)にする
休日希望,当直希望があれば、当直,休日(1〜),当直でも良い

4
スケジュール表の変更方法
当日から来月のスケジュール表を再計算する。
3 で記入した希望日は変更しない
特に人物の組み合わせでランダムになっていると大きく変更される。

5
人員の増員時の方法
専任職員増 行を挿入し、名前 所属 専門 初日 を記入
委員職員増 最終行の下に、名前 所属 専門 初日 を記入
初日の記入を忘れずに、スケジュール表の再計算をする

人員の減員時の方法
終日を記入
終日から一月以上過ぎていること
その人物の行を削除する

6 質問
休日希望はどれぐらいの頻度か
当直希望はどれぐらいの頻度か
当直は少ない方が良いと感じているのか
電気担当、空調担当、水道担当の中で良い悪いは無いのか

7
例外1
専任職員全員が当直無(忘年会等)の時、委員職員5人当直する
その時の記入方法・・・委員職員5人を当直希望と前もって記入する
その時、当直,休日(1〜),当直でも良い

例外2
委員職員全員が当直無(忘年会等)の時、専任職員5人当直する
その時の記入方法・・・委員職員全員を休日希望と前もって記入する
委員職員 - 0人が二日できる
その時、当直,休日(1〜),当直でも良い

8 意味不明、どういう処理だか解らない
当直の回数をはじめに指定
・金曜日と土曜日当直した人は、半休となり0.5日とする。

  ・半休二つがあったら、1日休みとする
・・・・休みだから何
祝日の扱い

(トラ) 2017/02/15(水) 14:17


 次のトピに続いているみたいです。
[[20170217080857]]
(通りすがり) 2017/02/18(土) 07:51

トラ様へ
返信遅れてすみません。
今年4月からルール変えまして、条件相談中です、
迷惑を掛けますがしばらくお持ち下さい。
今日か明日、投稿する予定です。
申し訳がありません。
(SinNeo) 2017/02/18(土) 17:15

トラ様へ
返信遅れて申し訳がありません。
コード表ありがとうございます。

この通り条件いいと思いますが、今年4月からルール変更がありまして、条件相談し上記の条件の修正・追加作成しましたので下記の条件で大丈夫でしょうか?

文字変更

委員職員 → 委託職員
電気当直担当 → 中央棟当直「当」
水道当直担当 → 入院棟当直「入」
空調当直担当 → 防災当直「防」

1、当直
・当直のない日は、1年を通して一日もない (祝日も当直をする)
・当直は、午前8時半から翌日の午前8時半まで
・連続当直は無し 連続当直・・・当直明けからすぐに次の当直に入ること
・当直は、5人で行う
・中央棟担当が3人、入院棟担当が1人、防災担当が1人で行う
・シフトスケジュール表は来月まで作成する
・同姓同名は避ける、片方を平仮名にするとかする
・半日当直とかは無し
・出来れば当直は、現在5人で行うが、将来、増やす(減らす)可能性がありますので、当直人数変更を出来るようにしたい
・当直基本、専任職員‐3人以上 委託職員‐2人以上(出来れば、将来、専任職員当直減らし委託職員増やす可能性がありますので、当直人数変更を出来るようにしたい)
・各1人 金曜日当直1回 土曜日当直1回 日曜日当直1回する事(専任職員だけなんけど、将来、専任職員も委託職員も回数選べるようにしたい)
・当直平均化
・中央棟当直だけの人(監視責任者の為)を設定したい (理想ですが、別のシートで各1人ずつ当直の別々チェックボックスような入れたり外したりようなしたい。)
・資格によって、防災当直だけ除いて中央棟当直と入院当直担当する。(入院当直だけ除いて中央棟当直と防災当直担当する。)(理想ですが、別のシートで各1人ずつ別々チェックボックスような入れたり外したりようなしたい。)

2、人数・回数
・専任職員は、0〜40人(理想)
・委託職員は、0〜40人(理想)
・専任職員、委託職員の順に名簿に記入
・専任、委員で当直回数を区別しない
・途中で参加する人は、E列の該当行にその開始日を入れる (シリアル値)
・途中で終わる人は、F列の該当行にその終了日を入れる (シリアル値)
・各1人 中央棟当直回数は制限なし
・各1人 入院棟当直回数は1〜3回
・各1人 防災当直回数は1〜3回
・前々月、前月、当月での当直回数の平均化
・土日の当直の平均化・・・祝日は無視する
・各1人当直回数は、月によって6〜8回

3、予定・休日・メンバー・表示
・休日希望を入力できる、休日直前日の当直は不可
・当直希望を入力できる・・・連続当直は無
・人物の組み合わせはランダムによって同じメンバーになっても良い
・休日希望,当直希望が無ければ、当直,休日(3〜2),当直,休日(3〜2),当直,休日(3〜2)にする →なし
・基本 専任職員の休日は、6回 委託職員の休日は、8回(理想、休日回数変更したい。)
・休日希望はどれぐらいの頻度か→専任職員の休日は、月によって6〜8回 委託職員の休日は、月によって6〜9回
・基本、土曜日→「週」 日曜日→「休」と表示したい
・出張→「出」 有休→「有」 代休→「代」当直明け→「×」施設→「施」と表示したい
・予定→「予」と表示するが、出来れば非表示したい
・出来れば、別のシートで自分で2つの上みたく入力してリフトして選びたい、そうすれば各1人別のシート作りたい。

4、スケジュール表の変更方法
当日から来月のスケジュール表を再計算する。
3で記入した希望日は変更しない。ちゃんと締め切りがあります。

5、人員の増員時の方法(いいと思います)
専任職員増 行を挿入し、名前 所属 専門 初日 を記入
委員職員増 最終行の下に、名前 所属 専門 初日 を記入
初日の記入を忘れずに、スケジュール表の再計算をする
人員の減員時の方法
終日を記入
終日から一月以上過ぎていること
その人物の行を削除する

6、日勤(出来れば)
・日勤は、中央棟日勤、入院棟日勤、大学棟日勤3つあります。
・回数は制限なし (出来れば、中央棟日勤だけの人(監視責任者のため)設定したい )
 (中央棟日勤だけの人いますが、たまに入院棟・大学棟日勤、数回したい)
 (理想ですが、別のシートで各1人ずつ別々チェックボックスような入れたり外したりようなしたい。)
・基本
 中央棟日勤は、当直や休日など以外残りが中央棟日勤
 入院棟日勤は、2人
 大学棟日勤は、2人
・表示はなしで、背色したい(7、色へ)

7、色
・中央棟日勤→塗るつぶしなし
・入院棟日勤→白 背1、黒+基本色25%
・大学棟日勤→白 背1、黒+基本色50%
・中央棟当直→塗るつぶしなし
・中央棟当直3人内1人(中央棟当直だけの人は除いて)→白 背1、黒+基本色50%
・入院棟当直→白 背1、黒+基本色25%
・防災当直→白 背1、黒+基本色25%
・出張→オレンジ
・施設→オリーブ、アクセント3、白+基本60%

8、例外
例外1
専任職員全員が当直無(忘年会等)の時、委員職員5人当直する
その時の記入方法・・・委員職員5人を当直希望と前もって記入する
その時、当直,休日(1〜),当直でも良い (休日,当直でも良い)

例外2
委員職員全員が当直無(忘年会等)の時、専任職員5人当直する
その時の記入方法・・・委員職員全員を休日希望と前もって記入する
委員職員 - 0人が二日できる
その時、当直,休日(1〜),当直でも良い (休日,当直でも良い)

言葉が悪いのは、分かってますが
マリオ様が作ったファイルような(すみません)みたくが分かりやすくていいなと思います、、
VBA初心者ですみません。
迷惑をかけて申し訳がありません。
勉強になりますのでお手数ですが、よろしくお願い致します。
何かあれば言ってください。

気にしないで下さい↓↓
当直の回数をはじめに指定
・金曜日と土曜日当直した人は、半休となり0.5日とする。

  ・半休二つがあったら、1日休みとする
・・・・休みだから何
祝日の扱い

(SinNeo) 2017/02/19(日) 04:18


コメント返信:

[ 一覧(最新更新順) ]


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