【Excel VBAで売上分析】売上金額が低い時の状況把握と推移グラフ化の方法

 

「なんだか今月、売上が低い気がする…」

そんなモヤモヤを感じたとき、なんとなくの感覚だけで判断するのではなく、データを使って冷静に状況を把握することが大切です。

 

この記事では、売上金額が低いと感じたときに、まず“事実”を見える化するためのExcel分析方法をご紹介します。

 

📌 「これ、自動化できたらラクなのに…」と思ったこと、ありませんか?
実はその作業、Excelマクロで簡単に自動化できるかもしれません。
「でもマクロって難しそう…」という方のために、完全初心者向けの入門記事をご用意しました!

👇実務で“そのまま使える”テンプレ付きで、コピペするだけ
初心者向けエクセルマクロの作り方を解説|コピペOK実務テンプレ付き

 

【初心者向け】Excelマクロ記事はここをクリックで一覧表示します

 

売上金額が低い状況をデータで見える化するための準備

 

まずは、売上の状況を視覚化できるようにする準備から始めましょう。エクセルで分析するには、元となる売上データが必要です。

 

■ 売上データCSVファイルについて

 

売上データは、たとえば以下のようなCSV形式で出力されていることが多いです。

 

売上データCSVファイル

 

 

 

 

このようなCSVファイルをExcelに読み込めば、日付ごとの売上推移の売上状況を視覚的に把握できます。

 

Excel VBAで売上分析を行う方法|フォーム作成から集計・グラフ化まで

 

次に、実際にどのように分析を進めていくのかを解説します。

 

1. 準備した売上データCSVをExcelbookに保存

2. Excelbookの売上データを元に必要な項目を集計

3. 売上集計したシートをもとに日別売上推移をグラフ化

 

たったこれだけで、どの日に売上が低かったのか、逆に高かったのかが一目でわかるようになります。

 

■ フォーム作成手順

売上分析Ver01エクセルVBAのフォーム

 

■ 売上データから必要項目を自動集計する

売上集計元データ

 

 

 

 

 

 

 

 

 

■ 集計データを基に日別売上推移をグラフ化する手順

売上集計シート

 

グラフ日別売上推移

 

この日別売上推移グラフをチェックすれば、どの日に売上が前年同日より低かったのか、状況がすぐにわかります。

 

 

 

 

 

 

 

 

 

 

【コピペOK】売上分析に使えるExcel VBAコード

 

エクセルVBAで自動化したい場合、以下のコードで日別売上の集計グラフを作ることが可能です。

 

ThisWorkbookモジュール用コード

 

  1. Option Explicit
  2. Private Sub Workbook_Open()
  3.     UserForm1.Show vbModeless ' モーダルエラーを回避
  4. End Sub

 

フォームモジュール用コード

 

  1. Option Explicit
  2. Private Sub UserForm_Initialize()
  3.     ' フォーム初期化時にウィンドウを最小化し、フォームを前面に出す
  4.     Application.WindowState = xlMinimized
  5.     Me.Show vbModeless
  6. End Sub
  7. Private Sub btnSelectCSVFolder_Click()
  8.     Dim fldr As FileDialog
  9.     Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
  10.     
  11.     If fldr.Show = -1 Then
  12.         txtCSVFolder.Value = fldr.SelectedItems(1)
  13.     End If
  14. End Sub
  15. Private Sub btnSelectOutputFolder_Click()
  16.     Dim fldr As FileDialog
  17.     Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
  18.     
  19.     If fldr.Show = -1 Then
  20.         txtOutputFolder.Value = fldr.SelectedItems(1)
  21.     End If
  22. End Sub
  23. Private Sub btnImportCSV_Click()
  24.     If txtCSVFolder.Value = "" Then
  25.         MsgBox "CSVフォルダを指定してください。", vbExclamation
  26.         Exit Sub
  27.     End If
  28.     If Not IsDate(txtStartDate.Value) Or Not IsDate(txtEndDate.Value) Then
  29.         MsgBox "日付を正しく入力してください。(例:2024/02/01)", vbExclamation
  30.         Exit Sub
  31.     End If
  32.     Dim startDate As Date, endDate As Date
  33.     startDate = CDate(txtStartDate.Value)
  34.     endDate = CDate(txtEndDate.Value)
  35.     If startDate > endDate Then
  36.         MsgBox "開始日は終了日より前にしてください。", vbExclamation
  37.         Exit Sub
  38.     End If
  39.     
  40.     Call ImportCSVData(txtCSVFolder.Value, startDate, endDate)
  41.     ' フォームを前面に戻す
  42.     Me.Hide
  43.     Application.WindowState = xlMinimized
  44.     Me.Show vbModeless
  45. End Sub
  46. Private Sub btnRun_Click()
  47.     If txtOutputFolder.Value = "" Then
  48.         MsgBox "保存先フォルダを指定してください。", vbExclamation
  49.         Exit Sub
  50.     End If
  51.     
  52.     Dim startDate As Date, endDate As Date
  53.     startDate = CDate(txtStartDate.Value)
  54.     endDate = CDate(txtEndDate.Value)
  55.     
  56.     Call GenerateReport(txtOutputFolder.Value, startDate, endDate)
  57.     
  58.     ' フォームを前面に戻す
  59.     Me.Hide
  60.     Application.WindowState = xlMinimized
  61.     Me.Show vbModeless
  62. End Sub
  63. Private Sub btnClose_Click()
  64.     ThisWorkbook.Save
  65.     Application.Quit
  66. End Sub

 

自分の実力を客観的にチェックしたい…。そんな方のために、自分に合ったスタート地点がわかる無料のExcelVBAベーシック選択問題集をご用意しました。

👉無料ExcelVBAベーシック選択問題138問

 

標準モジュール用コード

 

  1. Option Explicit
  2. Sub ImportCSVData(csvFolder As String, startDate As Date, endDate As Date)
  3.     Application.ScreenUpdating = False
  4.     Application.EnableEvents = False
  5.     Application.DisplayAlerts = False
  6.     
  7.     Dim fName As String, fullPath As String
  8.     Dim wbCSV As Workbook, wsCSV As Worksheet
  9.     Dim targetWb As Workbook, wsTarget As Worksheet
  10.     Dim lastRow As Long, r As Long, nextRow As Long
  11.     Dim orderDate As Date
  12.     Dim headerWritten As Boolean
  13.     ' 保存用ブックのパス
  14.     Dim savePath As String
  15.     savePath = csvFolder & "\売上集計元データ.xlsx"
  16.     ' 既存 or 新規作成
  17.     On Error Resume Next
  18.     Set targetWb = Workbooks.Open(savePath)
  19.     If targetWb Is Nothing Then
  20.         Set targetWb = Workbooks.Add
  21.         targetWb.SaveAs Filename:=savePath
  22.     End If
  23.     On Error GoTo 0
  24.     ' シート取得
  25.     On Error Resume Next
  26.     Set wsTarget = targetWb.Sheets("元データ")
  27.     If wsTarget Is Nothing Then
  28.         Set wsTarget = targetWb.Sheets(1)
  29.         wsTarget.Name = "元データ"
  30.     End If
  31.     On Error GoTo 0
  32.     ' ヘッダー未設定の場合、1行目にヘッダー追加
  33.     If wsTarget.Cells(1, 1).Value = "" Then
  34.         wsTarget.Range("A1:K1").Value = Array("注文日", "注文番号", "顧客ID", "商品ID", "商品名", "カテゴリ", "単価", "数量", "金額", "クーポン割引", "ステータス")
  35.     End If
  36.     ' 次の行を取得(ヘッダー行の次)
  37.     nextRow = wsTarget.Cells(wsTarget.Rows.Count, 1).End(xlUp).Row + 1
  38.     ' CSV処理
  39.     fName = Dir(csvFolder & "\*.csv")
  40.     Do While fName <> ""
  41.         fullPath = csvFolder & "\" & fName
  42.         Set wbCSV = Workbooks.Open(fullPath)
  43.         Set wsCSV = wbCSV.Sheets(1)
  44.         lastRow = wsCSV.Cells(wsCSV.Rows.Count, 1).End(xlUp).Row
  45.         For r = 2 To lastRow
  46.             If IsDate(wsCSV.Cells(r, 1).Value) Then
  47.                 orderDate = CDate(wsCSV.Cells(r, 1).Value)
  48.                 If orderDate >= startDate And orderDate <= endDate Then
  49.                     wsTarget.Range("A" & nextRow & ":K" & nextRow).Value = wsCSV.Range("A" & r & ":K" & r).Value
  50.                     nextRow = nextRow + 1
  51.                 End If
  52.             End If
  53.         Next r
  54.         wbCSV.Close SaveChanges:=False
  55.         fName = Dir
  56.     Loop
  57.     
  58.     wsTarget.Cells.EntireColumn.AutoFit
  59.     ' カンマ編集(単価G列、金額I列、クーポン割引J列)
  60.     With wsTarget
  61.         .Columns("G").NumberFormat = "#,##0"
  62.         .Columns("I").NumberFormat = "#,##0"
  63.         .Columns("J").NumberFormat = "#,##0"
  64.     End With
  65.     
  66.     targetWb.Save
  67.     targetWb.Close
  68.     MsgBox "CSVの取り込みが完了しました。", vbInformation
  69.     
  70.     Application.ScreenUpdating = True
  71.     Application.EnableEvents = True
  72.     Application.DisplayAlerts = True
  73. End Sub
  74. Sub GenerateReport(outputFolder As String, startDate As Date, endDate As Date)
  75.     Application.ScreenUpdating = False
  76.     Application.EnableEvents = False
  77.     Application.DisplayAlerts = False
  78.     
  79.     Dim srcWb As Workbook, wsSrc As Worksheet
  80.     Dim salesDict As Object: Set salesDict = CreateObject("Scripting.Dictionary")
  81.     Dim salesDictLastYear As Object: Set salesDictLastYear = CreateObject("Scripting.Dictionary")
  82.     Dim orderDate As Date, amount As Double, discount As Double
  83.     Dim lastRow As Long, r As Long
  84.     ' 元データブックを開く
  85.     Set srcWb = Workbooks.Open(outputFolder & "\売上集計元データ.xlsx")
  86.     Set wsSrc = srcWb.Sheets("元データ")
  87.     lastRow = wsSrc.Cells(wsSrc.Rows.Count, 1).End(xlUp).Row
  88.     For r = 2 To lastRow
  89.         If IsDate(wsSrc.Cells(r, 1)) Then
  90.             orderDate = CDate(wsSrc.Cells(r, 1).Value)
  91.             amount = Val(wsSrc.Cells(r, 9).Value)
  92.             discount = Val(wsSrc.Cells(r, 10).Value)
  93.             If orderDate >= startDate And orderDate <= endDate Then
  94.                 If salesDict.exists(orderDate) Then
  95.                     salesDict(orderDate) = salesDict(orderDate) + (amount - discount)
  96.                 Else
  97.                     salesDict.Add orderDate, amount - discount
  98.                 End If
  99.             End If
  100.             ' 前年同日
  101.             If orderDate >= DateAdd("yyyy", -1, startDate) And orderDate <= DateAdd("yyyy", -1, endDate) Then
  102.                 If salesDictLastYear.exists(orderDate) Then
  103.                     salesDictLastYear(orderDate) = salesDictLastYear(orderDate) + (amount - discount)
  104.                 Else
  105.                     salesDictLastYear.Add orderDate, amount - discount
  106.                 End If
  107.             End If
  108.         End If
  109.     Next r
  110.     srcWb.Close SaveChanges:=False
  111.     If salesDict.Count = 0 Then
  112.         MsgBox "売上データが見つかりませんでした。", vbInformation
  113.         Exit Sub
  114.     End If
  115.     ' 新しいブックで集計
  116.     Dim newWb As Workbook: Set newWb = Workbooks.Add
  117.     Dim dest As Worksheet: Set dest = newWb.Sheets(1)
  118.     dest.Name = "売上集計"
  119.     dest.Range("A1:E1").Value = Array("日付", "売上金額", "前日差額", "伸び率", "前年同日売上")
  120.     Dim keys As Variant: keys = salesDict.keys
  121.     Call BubbleSortDates(keys)
  122.     Dim i As Long
  123.     For i = 0 To UBound(keys)
  124.         Dim dt As Date: dt = keys(i)
  125.         dest.Cells(i + 2, 1).Value = dt
  126.         dest.Cells(i + 2, 2).Value = salesDict(dt)
  127.         If i > 0 Then
  128.             Dim prev As Double
  129.             prev = salesDict(keys(i - 1))
  130.             dest.Cells(i + 2, 3).Value = salesDict(dt) - prev
  131.             If prev <> 0 Then
  132.                 dest.Cells(i + 2, 4).Value = Format((salesDict(dt) - prev) / prev, "0.00%")
  133.             End If
  134.         End If
  135.         ' 前年同日の値
  136.         Dim lastYearDate As Date: lastYearDate = DateAdd("yyyy", -1, dt)
  137.         If salesDictLastYear.exists(lastYearDate) Then
  138.             dest.Cells(i + 2, 5).Value = salesDictLastYear(lastYearDate)
  139.         Else
  140.             dest.Cells(i + 2, 5).Value = ""
  141.         End If
  142.     Next i
  143.     ' 複合グラフ作成
  144.     dest.Cells.EntireColumn.AutoFit
  145.     ' ========== 複合グラフ作成(列B:売上金額、列G:前年同日売上) ==========
  146.     Dim chObj As ChartObject
  147.     Dim chartSheet As Worksheet
  148.     On Error Resume Next
  149.     Set chartSheet = newWb.Sheets("グラフ日別売上推移")
  150.     On Error GoTo 0
  151.     If chartSheet Is Nothing Then
  152.         Set chartSheet = newWb.Sheets.Add(After:=dest)
  153.         chartSheet.Name = "グラフ日別売上推移"
  154.     Else
  155.         chartSheet.Cells.Clear
  156.     End If
  157.     'Dim chObj As ChartObject
  158.     Set chObj = chartSheet.ChartObjects.Add(Left:=50, Width:=700, Top:=30, Height:=350)
  159.     
  160.     With chObj.Chart
  161.         .ChartType = xlColumnClustered
  162.         .HasTitle = True
  163.         .ChartTitle.Text = "日別売上推移(当年:棒、前年:折線)"
  164.         .HasLegend = True
  165.         .Legend.Position = xlLegendPositionBottom
  166.         
  167.         ' データ系列をすべて削除
  168.         Do While .SeriesCollection.Count > 0
  169.             .SeriesCollection(1).Delete
  170.         Loop
  171.         ' 売上金額(棒グラフ)
  172.         .SeriesCollection.NewSeries
  173.         .SeriesCollection(1).XValues = dest.Range("A2:A" & salesDict.Count + 1)
  174.         .SeriesCollection(1).Values = dest.Range("B2:B" & salesDict.Count + 1)
  175.         .SeriesCollection(1).Name = "売上金額"
  176.         .SeriesCollection(1).ChartType = xlColumnClustered
  177.         .SeriesCollection(1).ApplyDataLabels 'データラベル追加
  178.         ' 前年同日売上(折れ線グラフ)
  179.         .SeriesCollection.NewSeries
  180.         .SeriesCollection(2).XValues = dest.Range("A2:A" & salesDict.Count + 1)
  181.         .SeriesCollection(2).Values = dest.Range("E2:E" & salesDict.Count + 1)
  182.         .SeriesCollection(2).Name = "前年同日売上"
  183.         .SeriesCollection(2).ChartType = xlLine
  184.         .SeriesCollection(2).Format.Line.Weight = 2.25
  185.         .SeriesCollection(2).ApplyDataLabels 'データラベル追加
  186.     End With
  187.     
  188.     ' カンマ編集(売上金額B列、前日差額C列、前年同日売上E列)
  189.     With dest
  190.         .Columns("B").NumberFormat = "#,##0"
  191.         .Columns("C").NumberFormat = "#,##0"
  192.         .Columns("E").NumberFormat = "#,##0"
  193.     End With
  194.     
  195.     ' 保存
  196.     Dim savePath As String
  197.     savePath = outputFolder & "\売上集計_" & Format(Now, "yyyymmdd_HHMMSS") & ".xlsx"
  198.     newWb.SaveAs Filename:=savePath
  199.     newWb.Close SaveChanges:=False
  200.     
  201.     MsgBox "集計ファイルを保存しました。" & vbCrLf & savePath, vbInformation
  202.     Application.ScreenUpdating = True
  203.     Application.EnableEvents = True
  204.     Application.DisplayAlerts = True
  205. End Sub
  206. Sub BubbleSortDates(arr As Variant)
  207.     Dim i As Long, j As Long, tmp
  208.     For i = LBound(arr) To UBound(arr) - 1
  209.         For j = i + 1 To UBound(arr)
  210.             If arr(i) > arr(j) Then
  211.                 tmp = arr(i)
  212.                 arr(i) = arr(j)
  213.                 arr(j) = tmp
  214.             End If
  215.         Next j
  216.     Next i
  217. End Sub

 

売上金額が低い原因を分析するための次のステップ

売上金額が低いという“状況”が可視化できたら、次に気になるのは、その「原因」。

 

「売上金額が低い原因が何かを知るエクセル分析のやり方」を、このコードをもとにもっと踏み込んで作成してください。

 

Excel VBAエキスパートベーシックとスタンダード、どちらを選べばいいか判断が難しい…。そんな方のために、自分に合ったスタート地点がわかる無料のExcelVBAベーシック選択問題集を用意しました。

👉無料ExcelVBAベーシック選択問題138問