Access (VBA)

Access VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10 Pro : Access 2013)
連続していることの検出(把握)・・
投稿日時: 20/07/06 12:46:44
投稿者: S.Kos

みなさま、こんにちは。
 
なんちゃらかんちゃらが「連続している」ことを検出(把握)しようとしています・・
 
次はある月のカレンダと、○(出席)×(欠席)で示す、二人の生徒の出欠席状況です
 日付→11 12 13 14 15 16 17 18 19 20 21 22 23
 曜日→水、木、金、土、日、月、火、水、木、金、土、日、月、
 A君→○ × × 休 休 × × × × × 休 休 ○
 B君→× × ○ 休 休 × × ○ × × 休 休 ×
 
二人とも「7日欠席」していますが、A君は「連続」していて、B君はそうではありません。
 
この違いを検出(把握)しよう、と考えていますが、メドが立たちません。
 
1 どんなデータ構成で、
2 どのようなアルゴリズムで、
 
これを把握できるでしょうか?
 

回答
投稿日時: 20/07/06 14:57:59
投稿者: Suzu

S.Kos さんの引用:
この違いを検出(把握)しよう、と考えていますが、メドが立たちません。
 
1 どんなデータ構成で、
2 どのようなアルゴリズムで、

 
提示された表そのもののデータをテーブルとするのか (これだと、一月ごとにテーブルが必要ですよね)
 
それとも、データベースらしく考えるなら
氏名	日付	出欠
A	2020/03/11	○
A	2020/03/12	×
A	2020/03/13	×
A	2020/03/14	休
A	2020/03/15	休
A	2020/03/16	×
A	2020/03/17	×
A	2020/03/18	×
A	2020/03/19	×
A	2020/03/20	×
A	2020/03/21	休
A	2020/03/22	休
A	2020/03/23	○
B	2020/03/11	×
B	2020/03/12	×
B	2020/03/13	○
B	2020/03/14	休
B	2020/03/15	休
B	2020/03/16	×
B	2020/03/17	×
B	2020/03/18	○
B	2020/03/19	×
B	2020/03/20	×
B	2020/03/21	休
B	2020/03/22	休
B	2020/03/23	×

の様にするのか。
 
どの様なデータを画面から入力し、最終的にどのような出力を行いたいのかを明らかにしましょう。
それが決まらないとテーブル構造が決まりません。
 
テーブル構造が変われば 結果を得る為の手法も変わるでしょう。
 
また、月ごとの走査だけでよいのか、月またぎもあるのか 等の条件が変われば
効率的な計算方法も変わるでしょうね。
 
 
 
先に提示した テーブル構造 列に、氏名、日付、出欠
氏名、日付の年月部分を指定して得たいなら
私ならレコードセットを呼び出しレコード走査してしまいます。
 
'引数
' 氏名
' 年月 を yyyymm 形式

Function getContinuousAbsence(strName As String, strYearAndMonth As String) As Integer
    Dim rs As New ADODB.Recordset

    Dim sDate As Date
    Dim eDate As Date

    Dim strSQL As String

    Dim cntAbsence As Integer
    Dim MaxAbsence As Integer
    Dim absAbsence As Boolean

    sDate = DateSerial(Left(strYearAndMonth, 4), Mid(strYearAndMonth, 5, 2), 1)
    eDate = DateAdd("m", 1, sDate) - 1

    strSQL = "SELECT 日付, 出欠 FROM 出欠テーブル WHERE 氏名=""" & strName & """ AND 日付 BETWEEN #" & sDate & "# AND #" & eDate & "# ORDER BY 日付;"
'    Debug.Print strSQL
    rs.Open strSQL, CurrentProject.Connection

    cntAbsence = 0
    MaxAbsence = 0

    Do While Not rs.EOF
        Select Case rs![出欠]
            Case "○"
                If MaxAbsence < cntAbsence Then MaxAbsence = cntAbsence
                cntAbsence = 0
            Case "×"
                cntAbsence = cntAbsence + 1
            Case "休"
        End Select
        rs.MoveNext
    Loop

    rs.Close
    If MaxAbsence < cntAbsence Then MaxAbsence = cntAbsence
    getContinuousAbsence = MaxAbsence
End Function

 
呼び出し例
Sub TEST()
    MsgBox getContinuousAbsence("A", "202003")
    MsgBox getContinuousAbsence("B", "202003")
End Sub

 
クエリ でも得られるでしょうが、多段のサブクエリになる方法しか思いつかなかったので ^^;

投稿日時: 20/07/06 21:07:40
投稿者: S.Kos

ああ、Suzuさん、こちらでもご教示のほど、ありがとうございます。
 
>また、月ごとの走査だけでよいのか、月またぎもあるのか 等の条件が変われば
>効率的な計算方法も変わるでしょうね。
>
ご指摘の点、尤もです。
 
その他にも休日と平日の入れ換えもあって、条件はいささか錯綜しています。
それ故に、プリミィティブな箇所を切り出し、「どんなデータ構成で」とお尋ねしました。
 
>私ならレコードセットを呼び出しレコード走査してしまいます。
>
やはり、コレが確実ですよね。
データ構成如何で、なにかしら「スマートなアルゴリズム」があるかな? と・・
 
安心(?)して、力技(苦笑)に取り掛かります。
ご教示のほど、重ねて御礼申し上げます。