[[20251030224114]] 『シートにまたがるデータの平均を求めるマクロは』(Noz) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) |

| 全文検索 | 過去ログ ]

 

『シートにまたがるデータの平均を求めるマクロは』(Noz)

1月〜12月までの12枚のシートがあり、そこには日付とその日の売り上げを入力します(Aのセルには日 Bのセルにはその日の売り上げ)
そして13枚目のシートに任意の10日間の売り上げ平均を表示したいと考えています。同じ月内(同一シート)の10日間の平均を求める場合と次の月(次のシート)にまたがる10日間(たとえば10月25日から11月3日までの10日間の平均)がありますが、これを表示できるマクロを教えてください。
よろしくお願いします。

< 使用 Excel:Excel2021、使用 OS:Windows11 >


どのへんで詰まってますか?
単純に考えれば
 1日目と10日目が同じ月か
     SUMIFS関数で1〜10日目の合計値を求めて10で割る
 ちがうなら
     SUMIFS関数で1日目の月のシートを対象に1〜10日目の合計値を求める
     SUMIFS関数で10日目の月のシートを対象に1〜10日目の合計値を求める
     上記を合算して10で割る
 分岐処理終了
 結果出力

上記のような感じで考えればよいとおもいます。
(マクロ以外だったらもっと妙案ありそうですが、思いつきませんでした。)

(もこな2) 2025/10/31(金) 08:20:35


Vstackでまとめて、用心の為sortかけてFilterで抽出後アベレージで求める
のも一案かもですね。。。(*^^*)
外してましたらお許しを。。。m(__)m
(隠居Z) 2025/10/31(金) 09:31:13

月別のシートの表を、1つの表にまとめちゃえば、
その後は難しく考えなくてもいいのでは?
年や年度も跨ぐ場合もありますよね???
(まっつわん) 2025/10/31(金) 09:53:35

 関数なら
 =LET(sday,DATEVALUE("2025/10/4"),eday,DATEVALUE("2025/10/14"),
     AVERAGE(
     FILTER('1月'!B:B,('1月'!A:A>=sday)*('1月'!A:A<=eday),""),
     FILTER('2月'!B:B,('2月'!A:A>=sday)*('2月'!A:A<=eday),""),
         ・
         ・
         ・             
     FILTER('12月'!B:B,('2月'!A:A>=sday)*('12月'!A:A<=eday),"")
    )
 )
 と、シートの分だけFILTER関数を使うとできそうです。
 2021なので便利な関数が使えないのが痛いですね。

 マクロなら地道にセルの値を拾っていけば良さそう
(´・ω・`) 2025/10/31(金) 11:04:38

 雰囲気はこんな感じですが、B列が空だと0として扱われるので、AVERAGE関数とはちょっと違います。

 Function Average10Days(sday As Date)
   Dim eday As Date
   Dim S As Double, Ccount As Double
   eday = sday + 10
   S = 0
   For m = 1 To 12
     With Worksheets(Format(m, "0月"))
        For r = 1 To 40
          If .Cells(r, 1) >= sday And .Cells(r, 1).Value <= eday Then
             S = S + .Cells(r, 2)
             count = count + 1
          End If
        Next
     End With
   Next
   Average10Days = S / count
 End Function

(´・ω・`) 2025/10/31(金) 11:25:53


4名の方ご教示ありがとうございます。当方はまだまだエクセルの奥深さについていけない初心者に毛がはえた程度のものですので、もこな2さんの「どこで詰まっているのか」という問いにすべてと言うしかありません。勉強しながらやっていきたいと思います。
(Noz) 2025/10/31(金) 11:37:45

>もこな2さんの「どこで詰まっているのか」という問いにすべてと言うしかありません。
それなら、いきなりVBAのコードを考えるのではなく、
まずは、自分が手作業ですることを箇条書きで書き上げてみてください。

質問の例:「10月25日から11月3日までの10日間の平均」
で考えてみます。

 1、平均を表示するシートに日付(いつから)と日付(いつまで)を入力する
 2、日付(いつから)と日付(いつまで)の間が何日あるか計算しておく(今回の例ではは10日)
 3、日付(いつから)、10日間を足して月末日付を超える場合、日付(いつから)から月末まで何日あるか計算しておく
 4、10日間−(日付(いつから)から月末まで何日あるか)で翌月の何日分を取ればよいか計算しておく
 5、日付(いつから)の月のシートを選択する
 6、日付(いつから)の日のセルを選択する
 7、その日から10日分のB列(売り上げ)をのセルを選択する
   ただし、日付(いつから)から10日分が月末日付を超える場合、3で計算された分の売り上げを足す
 8、日付(いつから)から10日分が月末日付を超える場合、次の月のシートを選択する
 9、日付(いつから)から10日分が月末日付を超える場合、次の月の4で計算された日数分の売り上げを足す
10、足された売り上げを2で計算された日数(今回は10日間)で割る

という感じです。
これってExcelのスキルとしては、シートの選択、セルの選択、セルの範囲を指定する
というくらいですよね。
>「初心者に毛がはえた程度」
でも可能ですよね。

そして、これら1つずつをVBAのコードで書いてみる。
2でつまづいているのなら、2の部分だけを質問してみる。
2がうまくいったら3をやってみる。
3でつまづいたら、また3の部分だけを質問してみる



という様にやってみてください。
そうすれば、自分がどこでつまづいているか明確になりますし、
まず日本語で箇条書きにするという習慣をつけてみてください。

こんなことを繰り返していると、自然とある程度できるようになりますよ。

(匿名) 2025/10/31(金) 13:51:32


■1
マクロは別に魔法とかではなく、手作業をエクセル君に代わりにやってもらっているに過ぎません。
なので、マクロでやろうと思い立ったからには何らかの考えはあるとおもうんですが・・・

また、完成していなくとも現状のコードを示していただくことで、シートの構成などがわかったり、どの辺を勘違いされているのかわかったりします。

なので、何らかの着手をされているのであれば、コードを示した上で、〜〜になるはずが〜〜になってしまうなど具体的な説明をされた方が、回答者とのキャッチボールが少なくなると思います。

■2
今回のケースで気になるところは「Aのセルには日」と表現されているところです。
A列が"日付"(年月の情報を含んでいる)のであれば話は単純で、

 =SUMIFS('1月'!B1:B31, '1月'!A1:A31, ">="&A1, '1月'!A1:A31, "<"&A1+10)
 =SUMIFS('2月'!B1:B31, '2月'!A1:A31, ">="&A1, '2月'!A1:A31, "<"&A1+10)
 ・
 ・

のような感じで、ほかの月シートにダブって存在するわけ無いので、一旦各月シートでSUMIFS関数で合計を求め、さらにその合計を求めてから10で割ればよいでしょう

■3
そうで無くて、日だけ(年月の情報が含まれない)ならば、先に示したようにどの月を見ればよいか特定した上で、最大で2つのシートの合計を出した上で10で割ればよいでしょう

■4
いずれにせよ、勉強しながらやってみるということなので、とりあえず手を付けてみて、うまくいかなければ、コード(と必要に応じてデータ例)を示して質問されるとよいと思います。

(もこな2) 2025/11/02(日) 16:33:51


しばらくはなれていました。皆さんアドバイスありがとうございました。課題にします。
(Noz) 2025/11/07(金) 10:40:26

 自分で学習・実装するのであればそちら優先ください。
 中身は完全に理解できなくとも機能が実現できれば良いという場合は御参考に。

 AIの回答と書けというARA5H1もいるので、一応AI回答ですと明記します。
 ---------------------------------
 以下に「1月〜12月」までのシート(名前が「1月」「2月」…「12月」)に、
 それぞれ A列=日付、B列=売上 がある前提で、
 「13枚目のシート」(名前は「平均計算」など)において、
 任意の開始日と10日間平均の売上を表示するVBAマクロ を示します。

 🔧 マクロの概要
 「平均計算」シートに
 セルB1:開始日(例:2025/10/25)
 セルB2:平均日数(例:10)
 セルB3:計算結果(売上平均値)が表示される

 各月シート(1月〜12月)に
 A列:日付(例:2025/10/1 のように日付型で入力)

 B列:売上
 期間が月をまたいでも自動で平均計算します。

 💻 VBAコード
 Sub 平均売上計算()
    Dim wsAvg As Worksheet
    Dim ws As Worksheet
    Dim dStart As Date
    Dim dEnd As Date
    Dim total As Double
    Dim count As Long
    Dim i As Long
    Dim monthName As String
    Dim d As Date
    Dim val As Variant

    ' 平均計算シートを指定
    Set wsAvg = ThisWorkbook.Sheets("平均計算")

    ' 開始日と日数を取得
    dStart = wsAvg.Range("B1").Value
    dEnd = dStart + wsAvg.Range("B2").Value - 1

    total = 0
    count = 0

    ' 開始日から終了日まで繰り返し
    For d = dStart To dEnd
        ' 月名(シート名)を取得(例:10月)
        monthName = Month(d) & "月"

        ' 対応する月シートが存在する場合のみ処理
        On Error Resume Next
        Set ws = ThisWorkbook.Sheets(monthName)
        On Error GoTo 0

        If Not ws Is Nothing Then
            ' 該当日付を検索
            For i = 1 To ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
                If ws.Cells(i, "A").Value = d Then
                    val = ws.Cells(i, "B").Value
                    If IsNumeric(val) And Not IsEmpty(val) Then
                        total = total + val
                        count = count + 1
                    End If
                    Exit For
                End If
            Next i
        End If
        Set ws = Nothing
    Next d

    ' 平均を出力
    If count > 0 Then
        wsAvg.Range("B3").Value = total / count
    Else
        wsAvg.Range("B3").Value = "データなし"
    End If
 End Sub

 🧭 使い方
 シート名を確認
 各月のシート名を「1月」「2月」…「12月」にしておきます。
 平均計算シートを作成し、B1に開始日、B2に日数を入力。
 例:
 B1:2025/10/25  
 B2:10

 VBAエディタ(Alt + F11)で新しいモジュールを挿入し、上のコードを貼り付けます。
 実行(F5)すると、B3に平均値が出ます。

 ✅ 補足
 開始日や日数を変えれば、どんな範囲でも対応可能です。
 日付は 正しい日付型(2025/10/25 など)で入力してください。

 10日間のうち売上が未入力の日があっても、自動で除外されます。
 月をまたいでも自動で次の月シートを参照します。

 ご希望があれば、
 「平均値のほかに合計も出す」
 「B3以降に履歴として複数行で結果を出す」
 などに対応した拡張版も作れます。

 どちらの形にしたいですか?
 おまけ
 シート名に依存しているので、以下、テストデータを作成するマクロです。
 白紙で作成したEXCELに下記のマクロを置き、CreateMonthlySheetsを実行で、上のマクロを実行する準備ができます。

 Sub CreateMonthlySheets()
    Dim ws As Worksheet
    Dim monthName As String
    Dim i As Long, d As Long
    Dim daysInMonth As Long
    Dim startDate As Date

    Application.ScreenUpdating = False
    Set ws = CreateSheet("平均計算")
    ws.Range("A1:A3") = WorksheetFunction.Transpose(Array("開始日", "日数", "平均値"))

    ' 1月〜12月のシートを作成
    For i = 1 To 12
        Set ws = CreateSheet (i & "月")

        ' その月の初日と末日を取得
        startDate = DateSerial(Year(Date), i, 1)
        daysInMonth = Day(DateSerial(Year(Date), i + 1, 0))

        ' 見出し行
        ws.Range("A1").Value = "日"
        ws.Range("B1").Value = "売上(乱数)"
        ws.Range("A1:B1").Font.Bold = True

        ' A列に日付、B列に乱数を設定
        For d = 1 To daysInMonth
            ws.Cells(d + 1, 1).Value = startDate + d - 1
            ws.Cells(d + 1, 2).Value = Int((100000 - 10000 + 1) * Rnd + 10000)
        Next d

        ' 列幅調整
        ws.Columns("A:A").NumberFormatLocal = "YYYY/MM/DD"
        ws.Columns("A:B").AutoFit
    Next i

    Application.ScreenUpdating = True

    MsgBox "1月〜12月と集計シートを作成しました!", vbInformation
 End Sub

 Function CreateSheet(wsName) As Worksheet
    On Error Resume Next
    Application.DisplayAlerts = False
    Worksheets(wsName).Delete
    Application.DisplayAlerts = True
    On Error GoTo 0

    Set CreateSheet = Worksheets.Add(After:=Sheets(Sheets.count))
    CreateSheet.Name = wsName
 End Function

 自分で回答しないのか、という話もありましたが、
 後ろのおまけはAI回答を少しアレンジしました。
 といってもシート作成機能の関数化と集計シートの追加だけですが。
(英愛) 2025/11/08(土) 13:31:20

 課題として棚上げされてしまったようで残念です。
 メモしておいたものを供養のため投稿しておきます。南無。

 Sub test()
     Dim 開始日 As Date, 終了日 As Date
     Dim 日数 As Long
     Dim ws As Worksheet, wsNext As Worksheet
     Dim startRng As Range
     Dim rng1 As Range, rng2 As Range
     Dim days1 As Long
     Dim sum1 As Long, sum2 As Long
     Dim count1 As Long, count2 As Long
     Dim averageAmount As Double

     開始日 = Worksheets("計算").Range("A1")
     終了日 = Worksheets("計算").Range("A2")

     日数 = 終了日 - 開始日 + 1

     Set ws = Worksheets(Month(開始日) & "月")

     Set startRng = ws.Cells(Day(開始日), "A")
     days1 = Application.EoMonth(開始日, 0) - 開始日 + 1

     If days1 >= 日数 Then   '(1)10日間以上であれば、10日間の売上の合計を求める
         Set rng1 = startRng.Offset(0, 1).Resize(日数, 1)
         sum1 = Application.SUMIF(rng1, "<>""""")        '単にSUMを使用しても結果は同じ
         count1 = Application.COUNT(rng1)
         averageAmount = sum1 / count1
     Else                    '(2)10日に満たない場合は、当月末までの売上合計と翌月分を加算して平均を求める
         Set wsNext = Worksheets(Month(終了日) & "月")   '存在チェックは省略

         Set rng1 = startRng.Offset(0, 1).Resize(days1, 1)
         sum1 = Application.SUMIF(rng1, "<>""""")
         count1 = Application.COUNT(rng1)

         Set rng2 = wsNext.Range("B1").Resize(日数 - days1, 1)
         sum2 = Application.SUMIF(rng2, "<>""""")
         count2 = Application.COUNT(rng2)

         averageAmount = (sum1 + sum2) / (count1 + count2)
     End If
     Worksheets("計算").Range("A3") = averageAmount
 End Sub

(xyz) 2025/11/08(土) 15:52:59


英愛さん、xyzさん ありがとうございました。まだまだ自分一人の力ではお二人のVBAコードはわからないことだらけですが、なんとか自分でそれぞれの記述の意味を理解していきたいと思います。参考にします。
(Noz) 2025/11/14(金) 00:01:45

■5
「課題にします。」ということだったんで、てっきり課題として取り組むってことかと思いましたが、認識違いだったようですね。
トライして疑問点を挙げていただければ、深まる議論もあったかと思いますが残念でした。

私も、既に提案した方法も含めて3案ほど披露しておきます。

   Sub 研究用1()
        '「■2」のアプローチ 全シートを巡回
        Dim シート番号 As Long
        Dim 開始日 As Date
        Dim buf As Double '売上だから整数?

        開始日 = Worksheets(13).Range("A1").Value

        Stop 'ブレークポイントの代わり
        For シート番号 = 1 To 12
            With Worksheets(シート番号)
                buf = buf + WorksheetFunction.SumIfs(.Range("B2:B1000"), .Range("A2:A1000"), ">=" & 開始日, .Range("A2:A1000"), "<" & 開始日 + 10)
            End With
        Next シート番号

        Worksheets(13).Range("A2").Value = buf / 10
    End Sub
    '=====================================================================================================
    Sub 研究用2()
         '「■3」のアプローチ 最大2つのシートを巡回
        Dim MyArr As Variant
        Dim SH As Worksheet
        Dim 開始日 As Date
        Dim buf As Double '売上だから整数?

        開始日 = Worksheets(13).Range("A1").Value
        If Month(開始日) = Month(開始日 + 9) Then
            MyArr = Array(Month(開始日) & "月")
        Else
            MyArr = Array(Month(開始日) & "月", Month(開始日 + 9) & "月")
        End If

        Stop 'ブレークポイントの代わり
        For Each SH In Worksheets(MyArr)
            buf = buf + WorksheetFunction.SumIfs(SH.Range("B2:B1000"), SH.Range("A2:A1000"), ">=" & 開始日, SH.Range("A2:A1000"), "<" & 開始日 + 10)
        Next SH

        Worksheets(13).Range("A3").Value = buf / 10
    End Sub
    '=====================================================================================================
    Sub 研究用3()
        '別案 10日間のうち稼働日のみ
        Dim Mydic As Object
        Dim シート番号 As Long
        Dim データ行 As Long
        Dim 開始日 As Date, MyDate As Date

        Set Mydic = CreateObject("Scripting.Dictionary")
        開始日 = Worksheets(13).Range("A1").Value

        Stop 'ブレークポイントの代わり
        For シート番号 = 1 To 12
            With Worksheets(シート番号)
                For データ行 = 2 To .Cells(.Rows.Count, "A").End(xlUp).Row
                    If .Cells(データ行, "A").Value >= 開始日 And .Cells(データ行, "A").Value < 開始日 + 10 Then
                        MyDate = Int(.Cells(データ行, "A").Value)

                        If Mydic.Exists(MyDate) Then
                            Mydic(MyDate) = Mydic(MyDate) + .Cells(データ行, "B").Value
                        Else
                            Mydic.Add MyDate, .Cells(データ行, "B").Value
                        End If
                    End If
                Next データ行
            End With
        Next シート番号

        Worksheets(13).Range("A4").Value = WorksheetFunction.Sum(Mydic.Items) / Mydic.Count
    End Sub

(もこな2) 2025/11/18(火) 21:54:56


みなさん、貴重なアイデアありがとうございました。その後次のような表を作ってみました。1月〜12月までの表についてはA列に日付(2025/11/21の形式)B列には売上げ金額 C列には経費 D列にはBからCを引いた実利益 なお、1行目はデータなしで2行目に見出しをつけてあります。13枚目のC2に開始日入力 C3に終了日入力し、C4に売上げ平均 C5に経費平均 C6に実利益平均を表示させようとしています。
みなさんの意見を参考にして、そしてネットのサイトを利用して次のようなコードを作ってみましたが うまくいきません。マクロが動きません。
ご教示ください。
Sub SALES()
    Dim ws As Worksheet
    Dim wsResult As Worksheet
    Dim startDate As Date, endDate As Date
    Dim sumSales As Double, sumExpense As Double, sumProfit As Double
    Dim cnt As Long
    Dim lastRow As Long
    Dim i As Long

    Set wsResult = ThisWorkbook.Sheets("各平均")

    startDate = wsResult.Range("C2").Value
    endDate = wsResult.Range("C3").Value

    sumSales = 0
    sumExpense = 0
    sumProfit = 0
    cnt = 0

    For Each ws In ThisWorkbook.Sheets
        If ws.Index <= 12 Then
            lastRow = ws.Cells(ws.Rows.count, "A").End(xlUp).Row
            For i = 3 To lastRow
                If IsDate(ws.Cells(i, "A").Value) Then
                    If ws.Cells(i, "A").Value >= startDate And ws.Cells(i, "A").Value <= endDate Then

   sumSales = sumSales + ws.Cells(i, "B").Value
                        sumExpense = sumExpense + ws.Cells(i, "C").Value
                        sumProfit = sumProfit + ws.Cells(i, "D").Value
                        cnt = cnt + 1
                    End If
                End If
            Next i
        End If
    Next ws

    If cnt > 0 Then
        wsResult.Range("C4").Value = sumSales / cnt
        wsResult.Range("C5").Value = sumExpense / cnt
        wsResult.Range("C6").Value = sumProfit / cnt
    Else

wsResult.Range("C4").Value = "該当データなし"

        wsResult.Range("C5").Value = ""
        wsResult.Range("C6").Value = ""
    End If
End Sub

(N) 2025/11/21(金) 11:04:50


何回かこのコードをトライしているうちに動きました。初歩的なミスでマクロのボタンの設定がおかしかったみたいです。 上のコードをもっと簡潔にわかりやすくする等のアイデアがありましたらお願いいたします。
(Noz) 2025/11/21(金) 11:30:41

>上のコードをもっと簡潔にわかりやすくする等のアイデアがありましたらお願いいたします。
別の人(自分以外の人)のコードを読むのは大変です。
なぜなら、100人にコードを書いてもらったら100通りのコードができても
不思議はないからです。

私が前に挙げた例で説明します。

 1、平均を表示するシートに日付(いつから)と日付(いつまで)を入力する
 2、日付(いつから)と日付(いつまで)の間が何日あるか計算しておく(今回の例ではは10日)
 3、日付(いつから)、10日間を足して月末日付を超える場合、日付(いつから)から月末まで何日あるか計算しておく
 4、10日間−(日付(いつから)から月末まで何日あるか)で翌月の何日分を取ればよいか計算しておく
 5、日付(いつから)の月のシートを選択する
 6、日付(いつから)の日のセルを選択する
 7、その日から10日分のB列(売り上げ)をのセルを選択する
   ただし、日付(いつから)から10日分が月末日付を超える場合、3で計算された分の売り上げを足す
 8、日付(いつから)から10日分が月末日付を超える場合、次の月のシートを選択する
 9、日付(いつから)から10日分が月末日付を超える場合、次の月の4で計算された日数分の売り上げを足す
10、足された売り上げを2で計算された日数(今回は10日間)で割る

1は都度手入力するものなので、コードはいりません。
2は、例えば、
   「A1(いつから)とB1(いつまで)の間が何日あるか計算した結果をC1に表示する」
というコードを自分で調べながら書いてみてください。
【例】これは普段の私の欠き方とは違いますが、あえて「わかりやすく」書いてみました

 Dim dateFrom As Date
 Dim dateTo As Date
 Dim ret As Long

 dateFrom = Cells(1, 1).Value
 dateTo = Cells(1, 2).Value

 ret = dateTo - dateFrom
 Cells(1, 3).Value = ret

3は、C1の値に10日を足したものをD1に表示して、E1にA1から月末まで何日あるか計算した結果をF1に表示する



という様に1つずつ書いていく方法がよいと思います。
1つ1つコードを書こうとして、わからなければ、
このような掲示板に1つずつ質問していく。
これを繰り返すうちにVBAのコーディングができるようになると思います。

・・・
なので
「自分が手作業ですることを箇条書きで書き上げてみてください」
という事を例を挙げて説明したのです。
(匿名) 2025/11/21(金) 12:27:21


匿名様 ありがとうございました。以後気をつけていきたいと思います。
(Noz) 2025/11/21(金) 13:00:12

コメント返信:

[ 一覧(最新更新順) ]


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