« 2025年5月 | トップページ | 2025年7月 »

2025年6月

Officeテンプレート「現金出納帳」「活動資金管理表 (サークル・コミュニティー運営)」の改造

まえがき

MicrosoftがOfficeテンプレートを公開しています。
https://www.microsoft.com/ja-jp/office/pipc/

活動資金管理表 (サークル・コミュニティー運営)
https://www.microsoft.com/ja-jp/office/pipc/template/result.aspx?id=13261

現金出納帳
https://www.microsoft.com/ja-jp/office/pipc/template/result.aspx?id=13285

この2つを合体し、モダンExcel(Power Query, Power Pivot)で集計する検討をしてみました。
間違いや改善点などがあれば、コメントをください。
サンプルファイルには、各テーブルの関係を示すブロック図やDAX式の解説などを記載しています。

250630suitou01 250630suitou02 250630suitou03 250630suitou04 250630suitou05250630suitou06250630suitou07

ピボットテーブルの項目名は、集計の仕組みを理解しやすくするため、Excelが自動で付けた項目名にしています。重複しない任意の項目名に書き換えることは可能です。メジャーの名前も重複しない任意の名前に書き換えることができますが、リレーションとピボットテーブルの再設定やDAX式等の修正が必要になります。

1. 特徴

1) 予算と実績の2つの出納帳に予算と実績を入力します。継続して複数年度の入力が可能です。
入力時の科目をドロップダウンリストで入力することにより、科目名の揺れを無くします。

2) 次の集計を行います。①~④は、集計年度をスライサーで切り替えることができます。
① 予算と実績の科目別、月別の推移表。
② 収入、支出、残高の予算と実績の推移表。
③ 当年実績と前年実績との比較表。
④ 当年予算と前年実績との比較表。(予算作成時に使用)
⑤ 活動資金管理表。(当年度のみ)

3) 拡張性
データモデルから新しいピボットテーブルやメジャーを作成することで、任意の集計表やピボットグラフを作ることができます。

2. 注意事項

Excel for Microsoft 365 の Power QueryとPower Pivotで作成しています。Excel 2019以上が必要です。
検証が不十分なので、使用する場合は間違っていないかを確認し、自己責任で使用してください。

3. サンプルファイル

ダウンロード - 250626suitoutyou2.zip

4. 集計方法について

1) 繰越金の取扱い

  1. 前年度の繰越金を当年度の収入に入力してください。
  2. 当年度の収入の合計は、繰越金を含まない式にしています。

行を追加したときに残高の式が自動入力されるようにするため、出納帳をExcelのテーブルにしています。
テーブル化した状態で残高の先頭に前年度の繰越金を参照する式を入力すると、その下の参照式も繰越金を参照する式に変わってしまい、残高の計算式が消えてしまう問題があります。
そこで、繰越金を収入列に入力する規則にしました。ワークシートの残高式は、繰越金の場合に繰越金とする式にしました。(この場合でも参照式を入れるとコピーアイコンが出るので、コピーしないようにしてください。)
これにより、残高の計算式が変わる問題は解消されますが、単純に収入を合計すると繰越金が含まれてしまいます。
そこで、収入を合計するメジャーに繰越金を除く条件式を入れて合計することにしました。
ピボットテーブルの残高は、ワークシート式の値ではなく、収入と支出からメジャーで計算する方式にしました。
以上のことから、本例のメジャーは多少複雑になっています。

※ メジャーDAX式の解説は、サンプルファイルの「説明」シートを見て下さい。

メジャーが苦手な人は、Power Queryで繰越金をフィルタて取り除くとメジャーを簡単にすることができます。また、残高を収入と支出からメジャーで計算するのではなく、ワークシート式で計算した残高を参照するようにすると、メジャーが簡単になります。

2) カレンダーテーブル

カレンダーテーブルを生成するPower Query M言語のコードを直接書いて作成しました。年度始まりが4月以外の場合は、詳細エディタでコードを直接修正してください。
分からなければ、クリック操作で新しい年度列を作成するか、Excelでカレンダーテーブルを作成してください。

Excel Power Query Mでカレンダを作成し、メジャーで前の値との差を計算
https://bigarrow.tea-nifty.com/blog/2025/06/post-b14054.html

3) GETPIVOTDATAの年月

年月のキーにyy/mmのテキスト型を使用しています。
シリアル値を用いる時は「&TEXT(I25,"YYYY-MM-DD")&"T00:00:00]」のような参照式にします。
GETPIVOTDATA() with a pivot table from a data model
https://www.excelforum.com/excel-charting-and-pivots/1357126-getpivotdata-with-a-pivot-table-from-a-data-model.html

5. 参考

収入を入庫、支出を出荷、残高を在庫と考えると、生産管理に応用することができます。下記は、以前の生産管理の記事です。
Excelで在庫管理/生産管理(メジャーで期間末在庫を算出)
https://bigarrow.tea-nifty.com/blog/2025/06/post-3f6a32.html

6. 余談

Officeテンプレートの家計簿
https://www.microsoft.com/ja-jp/office/pipc/template/result.aspx?id=1390

ワークシート式とVBAを駆使した力作です。でも、データベースの考え方で言うと悪い方法です。データが分散しているので、式の間違いを起こしやすいです。年別の推移を見るもの面倒です。モダンExcelを用いれば、もっと簡単に間違いを起こしにくい表を作ることができます。

| | コメント (0)

Fujitsu LIFEBOOK AH54/H を無理やりWindows 11にしてみた

2012年製、Fujitsu LIFEBOOK AH54/H、Core i5-3210M(Ivy Bridge)、UEFIを RufusでWindows 11にしてみました。
このPCはWindows 10をサポートしていません。Windows 11に適合していません。
Windows 10にアップデートしていましたが非常に遅いので、Windows 11はクリーンインストールをしました。

1. 事前準備

1) FMVA54H用のWidows 7/8用のドライバー類を外部記録媒体にコピーします。
https://azby.fmworld.net/app/customer/mypc/view/select_product.vhtml

2) ドライブのエラーをチェックします。

3) アプリケーションのデータをコピーします。

4) リカバリーディスクを作成していない時は、プリインストールアプリのインストーラーなどをコピーします。また、必要なライセンス情報をメモします。スクロールパッドなどのドライバーは、リカバリーディスクのソフトウェアディスクに入ります。

5) 不要なファイルを削除し、ディスクのクリーンアップとブラウザのキャッシュの削除をします。

2. ディスクイメージのバックアップ

失敗に備えてバックアップをします。

Clonezilla : https://clonezilla.org/
左のメニューのLive CD/USBの説明を見て、ISOとZIPのどちらをダウンロードすべきかを決め、Downloadメニューからダウンロードします。
USBメモリを使用する場合は、ZIPを選びます。

Clonezillaの起動USBを作成し、Windows 10の再起動時に[F12]を押してブートメニューを出し、USBからClonezliiaを起動しました。
Beginners Mode、エラーチェックあり(手動修復)を選びました。それ以外は、初期値のままです。(圧縮はExpert Modeでマルチコアの方が速く小さくなるのですが、温度上昇が大きいので避けました。)

Clonezilla - システムバックアップ・リストア:https://donchibishell.hatenablog.com/entry/2021/10/15/160525

※ バックアップソフトは、ディスクイメージとリカバリー用のメディアを作成できるものが良いです。AH54/Hに付属のバックアップソフトは、Windows 10以降に未対応なので、使用できません。
※ ClonezillaはLinuxで動き、ディスクイメージをコピーするので、Windowsのバージョンに依存しません。表示がCUI、Linux用語、一部英語なので、誤ってバックアップすべきデータを消さないように注意してください。

3. インストールUSBメモリーの作成

RufusでWindwso 11のisoイメージをUSBメモリーに書き込みます。
パーティション構成:GPT
ファイルシステム:NTFS
✅ 4GB以上のRAN、セキュアブート及びTPM 2.0の要件を削除
✅ オンラインアカウントの要件を削除
✅ データ収集を無効化
✅ BitLocker 自動デバイス暗号化を無効化します

Rufus:https://rufus.ie/ja/
インストール要件を満たさないPCへのWindows11インストール:https://zenn.dev/isi00141/articles/e392efa754e170

[2025/12/21]rufus4.11p + 25H2はインストール失敗しました。rufus4.11p + 24H2はインストールできました。24H2をインストールした後、次の記事で25H2にしました。

4. Windows 11のインストール4

LANケーブルを抜いてインストールします。WiFiはONにしておきます。プロダクトキー無しでインストールします。WiFiに接続する画面になったら、接続しないで進むと、ローカルアカウント名の入力になります。これが、ユーザーフォルダ名になります。英文字が無難です。パスワードは空欄でもOKです。

Windowsのインストール完了後にインターネットに接続すると、ローカルアカウントでもライセンス認証されます。

インストールが完了したら、好みに応じてマイクロソフトアカウントにサインインします。サインインするとEdgeのお気に入りなどが同期します。

※ ネット接続できる状態だとマイクロソフトアカウントでのインストールになります。そうすると、以前の環境を引き継ぎます。

5. 不明なデバイス

デバイスマネージャで4つの不明なデバイスが発生します。そこで、次のドライバーをインストールします。

1) FUJ02B1デバイスドライバー / Windows 8
2) FUJ02E3デバイスドライバー / Windows 8
3) インテル アクティブ マネージメント テクノロジー ドライバー V8.1 / Windows 7

1~3)は富士通のサイトにあります。
機種別サポート情報・ダウンロード:型名:FMVA54HB
https://azby.fmworld.net/app/customer/mypc/view/select_product.vhtml

[2025/12/21] インテル アクティブ マネージメント テクノロジー ドライバー V8.1 は、富士通のサイトから消えました。なので、次のV9を使用しました。
Intel(R) Active Management Technology 9.5.14.1724 (16/05/2014)
https://support.ts.fujitsu.com/indexdownload.asp?Softwareguid=d99fb70e-47aa-4634-8a77-25c09ecda886
インテル(R) アクティブ マネジメント テクノロジー ドライバー Version 2407.6.1.0 は試してません。
https://azby.fmworld.net/app/customer/driversearch/pc/drvdownload?mode=1&driverNumber=E1034843

4) Realtek RTS5229 Memory Card Driver
これは次のサイトからダウンロードしてインストールします。
https://support.ts.fujitsu.com/indexdownload.asp?Softwareguid=42d51c00-9b23-4032-88ca-2c56ad120ead

以上で不明なデバイスが無くなります。

6. その他ソフト

次の1)~2)を富士通のサポートサイトからダウンロードしてインストールします。

1) バッテリユーティリティ / Windows 8
充電量を80%に制限できるソフトです。

2) Fujitsu BIOS Driver / Windows 8
これは何をしているのか分かりまんが、富士通がWindows 8にするときに入れるように指示しているので、入れました。

3) バッテリ充電制御アップデートツール
Windows Updateをすると「バッテリ充電制御アップデートツール」をダウンロードしてアップデートする指示が来るので、その指示に従いインストールします。

4) バッテリ充電制御ユーティリティ
Windowsを再起動すると「バッテリ充電制御ユーティリティ」のインストールを求められるので、指示に従いインストールします。
これでスタートアップに「FjBatteryLimitterRun,exe」が追加され、充電量が65%に制限されます。

5) タッチパッドSynapticsドライバー
リカバリーディスクの中のソフトウェアディスクのDrvCdSrc.exeからインストールすると、スクロールパッドが使えるようになります。

7. 結果

高速起動の起動時間は約1分弱で、HDDのアクセスランプが落ち着くのが約1.5分です。なので、Windows 7の初期状態と同じくらいかも知れません。更新前のWindos 10から比べると速くなりました。

現在のSSDのPCに比べると遅いのですが、今からSSDに投資するほどの価値は無いと思います。BluRayドライブ搭載なので、そこが希少価値かも知れません。
もし、SSDにするならWindows 11をインストールする前にSSDに交換すると手間が省けます。

Windows 11未対応のPCをWindows 11にした場合、後に不具合が出る可能性もあり、個人情報があるメインPCでの使用は避けたほうが良いと思います。使えなくなると非常に困る用途であれば、Windows 10のままで、延長プログラムを購入するのが良いでしょう。
Microsoft、「Windows 10」延命プログラム「ESU」をテスト開始、個人でもOK、無償オプションも
https://forest.watch.impress.co.jp/docs/news/2025455.html

古いPCのWindows 10の環境を引き継ぐ11への更新は、うまく行かないことが多いです。クリーンインストールの方が成功確率が高いです。但し、不明なデバイスが発生するので、適切なドライバをインストールする必要があります。


8. 参考記事

Notebook PC Fujitsu LIFEBOOK AH54/H Windows 7 -> 10
https://bigarrow.tea-nifty.com/blog/2016/05/notebook-pc-fuj.html

| | コメント (0)

Notebook PC Acer Aspire AS5750G-N78E/LKF Window 11

2011年発売、Core i7 2630QM(Sandy Bridge)、BIOS(MBR)のノートPCに Windows 11 24H2 を入れてみました。
元はHDD、Windows 7のPCですが、中古で購入したときにWindows 10になっていました。その後、HDDをSSDに置換していたものです。
このPCはWindows 10をサポートしていません。Windows 11の要件を満たしていません。

1. 手順

1) 現状PCのドライバのインストーラーとプリインストールソフトのコピー

a) PCのドライバーアップデート用のファイルを外部記憶媒体にコピーします。
b) プリインストールソフトのプロダクトIDをメモします。インストーラーが入っていれば、それをコピーしておきます。但し、バックアップソフトなどは新しいOSで動かないです。(⇒ 私はこれを忘れていたので、Office 2010のインストールができなくなりました。)
c) 必要なアプリケーションデータがあれば、コピーしてください。

※ 不明なデバイス用に必要なものは、後述の6)を見てください。
※ Acerのサイトからは消えているので、昔ダウンロードしたものを使用します。
https://www.acer.com/jp-ja/support/product-support/AS5750G/downloads
※ Windowsのライセンス情報は不要です。元が正規品であれば、ネットで自動認証されます。

余談:国内メーカでも古い製品のサポート情報が消えるところがあります。同時期のASUSのPCは、サポート情報が残っています。
ドライバーが自動的にアップデートされるアプリが入っているPCもありますが、それとは別にサポートにあるドライバーを保存しておいた方が良いでしょう。

2) 現在のドライブのバックアップ

失敗に備えてバックアップをします。

Clonezilla-live(20250512-plucky-amd64)でドライブを丸ごとバックアップしました。
BIOSメニューは[F2]、ブートメニューは[F12]です。起動時に[F12]を押してCD-ROMから起動しました。
Beginners modeを使用しました。PCが古いのでExpert modeでCPUの能力を攻めないほうが良いと思います。

Clonezilla : https://clonezilla.org/
Clonezilla - システムバックアップ・リストア:https://donchibishell.hatenablog.com/entry/2021/10/15/160525

※ チェック(手動修復)は入れたほうが良いです。(私はチェックをスキップしたので、エラーで戻せなくなりました。)
※ ClonezillaはLinuxで動いています。用語はLinuxの用語です。操作を間違うと残すべきデータを失うことになるので、十分注意してください。
※ Clonezillaでバックアップしたイメージから、一部のデータを読み取ることはできません。ドライブを丸ごとリストアする必要があります。 
※ PCメーカがプリインストールしているバックアップソフトは、新しいOSに対応しない可能性があります。なので、ドライブを丸ごとバックアップする場合は、PCのOSから起動しないものが良いです。

3) Rufus(4.9p)でWindows 11 24H2のセットアップUSBを作成

SSDがMBRなので、BIOSにしました。

rufusでWindwso 11のisoイメージをUSBメモリーに書き込みます。
パーティション構成:GPT
ファイルシステム:NTFS
4GB以上のRAN、セキュアブート及びTPM 2.0の要件を削除
オンラインアカウントの要件を削除
データ収集を無効化
BitLocker 自動デバイス暗号化を無効化します

Rufus:https://rufus.ie/ja/
インストール要件を満たさないPCへのWindows11インストール:https://zenn.dev/isi00141/articles/e392efa754e170

4) Windows 10からのOSアップグレード ⇒ 失敗!

Windows 10からsetup.exeを起動し、環境を引き継ぐ設定で更新しました。

- インストール終盤でエラーが発生し、自動的にWindows 10に戻す作業が始まりました。
- 再起動時にWindows 10と11のブートメニューが表示されました。ブートローダまでは戻っていないようです。
- ClonezillaでWindows 10に戻そうとしましたが、バックアップファイルのエラーで戻せませんでした[*1]。その結果、PCがWindowsの起動失敗を繰り返すようになり、起動不能になりました。

[*1] 原因は不明です。もしかするとバックアップを取ったHDD(2009年製)の不良かも知れません。

5) Windows 11のクリーンインストール

[F12]でBIOSのブートメニューを起動し、Windows 11のセットアップUSBを選択して起動しました。パーティション番号の大きい順にすべてのパーティションを削除してクリーンインストールをしました。

Windows 11 インストール時のディスクの詳細設定 24H2対応
https://www.pasoble.jp/windows/11/setup-customize-disk.html

6) 不明なデバイス

デバイスマネージャーで不明になっているものが3つあったので、ベンダーとデバイスIDを調べて、コピーしておいたPC用の次のアップデートをインストールしました。

a) カードリーダー
昔Acerのサイトにあったもの:CardReader_Broadcom_15.4.7.1_W8x64U_A.zip

b) インテルME
昔Acerのサイトにあったもの:MgmtEngine_Intel_8.1.0.1263_W8x64UW8x86U_A.zip

a)とb)で不明なデバイスは無くなりました。

※ Acerのサイトからドライバーをダウンロードしていなかった場合は、ネットでファイル名を検索すると、見つかる場合があります。但し、ウィルスに感染している場合もあるので、十分注意してください。サイトの評判を検索し、ウィルスチェッカで確認してください。

Windowsの不明なデバイスの確認と、そのドライバを探す方法
https://dot1.tv/windows-driver/

7) その他ドライバー

c) LAN
250623lan
ベンダーIDとデバイスIDの検索からチップを調べ、ドライバーを検索して見つけたもの(危険性は不明です。自己責任です。)
https://www.station-drivers.com/index.php?option=com_remository&Itemid=353&func=fileinfo&id=2065&lang=en
broadcom_lan_17.2.0.2(www.station-drivers.com).exe

インストール中にMicrosoft SNMP Serviceが検出されないとのメッセージが出ました。
250623lanerr

これは入れなくても良いと思われます。

d) タッチパッド
昔Acerのサイトにあったもの:TouchPad_ELANTECH_11.6.11.002_W8x64UW8x86U_A.zip
これをインストールして再起動するとシステムトレイアイコンに△!マークが付き動作しません。デバイスマネージャーでドライバの更新をすると解消されます。2本指スクロールが使えるようになりました。

e) プリンタドライバー
EPSONのプリンタドライバを入れたところ、E_IATIIGJ.EXEがスタートアップに登録されたので、無効にしました。
250623epson2

2. 結果

Intel HD Graphics driverでメモリ整合性の互換性エラーが出ます。これは、対応ドライバが無いので、メモリ整合性をOFFにして無視します。

SSDにしていることと、アプリやドライバを殆ど入れていないので、起動時間は最新のPCと変わりません。
軽いアプリなら十分使用できると思われます。

Windows 11未対応のPCをWindows 11にすると、将来不具合が出る可能性もあり、大事なデータや個人情報があるメインPCでの使用は避けたほうが良いと思います。使えなくなると非常に困る用途であれば、Windows 10のままで、延長プログラムを購入するのが良いでしょう。
Microsoft、「Windows 10」延命プログラム「ESU」をテスト開始、個人でもOK、無償オプションも
https://forest.watch.impress.co.jp/docs/news/2025455.html

古いPCのWindows 11の更新は、うまく行かないことが多いです。クリーンインストールの方が成功確率が高いです。但し、不明なデバイスが発生するので、適切なドライバをインストールする必要があります。

3. 関連記事

Notebook PC Acer Aspire AS5750G-N78E/LKF
https://bigarrow.tea-nifty.com/blog/2016/06/acer-aspire-as5.html


| | コメント (0)

Excelで加重移動平均を求める方法(ワークシート式とメジャー)

次のYouTubeで加重移動平均をする長いワークシート式の作り方が丁寧に紹介されています。

【Excel】加重移動平均ってなに?なんて今さら人に聞けない…
https://www.youtube.com/watch?v=CB0JASszr1w

これをメジャーDAX式で求める方法をChatGPTに聞いたので紹介します。他にもっと良い方法があるかも知れません。使用する際は、自己責任でお願いいたします。

まず、最初に前記YouTubeのワークシート式を紹介します。

1. ワークシート式

1) 表のレイアウト
250619wma01

2) 加重移動平均のワークシート式 By ExcelドカタCH

=LET(
  _日付気温列, TAKE(_気温データ,,2),
  _日付列,[日付],
  _当日, [@日付],
  _日付抽出条件, (_日付列 <= _当日) * (_日付列 > (_当日 - $C$2)),
  _日付抽出, FILTER(_日付気温列, _日付抽出条件),
  _日付降順, SORT(_日付抽出,,-1),
  _気温列, CHOOSECOLS(_日付降順, 2),
  _サンプル数, ROWS(_気温列),
  _重み, SEQUENCE(_サンプル数,, _サンプル数, -1),
  _結果, SUM(_気温列 * _重み) / SUM(_重み),
  _結果
)

【解説】
=LET(
  _日付気温列, TAKE(_気温データ,,2), // 日付と気温の2列の配列
  _日付列,[日付], // 日付の1列の配列
  _当日, [@日付], // 加重移動平均を算出する日

  // 当日 ~ 当日 - 平均する日数($C$2) の日付を抽出する条件
  _日付抽出条件, (_日付列 <= _当日) * (_日付列 > (_当日 - $C$2)),

  // 当日 ~ 当日 - 平均する日数($C$2) を抽出した結果の日付の配列
  _日付抽出, FILTER(_日付気温列, _日付抽出条件),

  _日付降順, SORT(_日付抽出,,-1), // 平均化する日付の配列を降順で並び替え
  _気温列, CHOOSECOLS(_日付降順, 2), // 平均化する温度の列(2列目)を抜き出した配列
  _サンプル数, ROWS(_気温列), // 平均化する温度の行数
  _重み, SEQUENCE(_サンプル数,, _サンプル数, -1), // サンプル数から1ずつ減少する配列
  _結果, SUM(_気温列 * _重み) / SUM(_重み), // SUM(気温 * 重み) / SUM(サンプル数)
  _結果
)

※ ワークシート式に//でコメントを入れることはできません。

2. 加重移動平均のメジャーDAX式

1つの加重移動平均を出すだけならワークシート式で良いと思いますが、複数の加重移動平均をピボットテーブルで出すなら、メジャーも有用だと思います。最初に1つの加重移動平均を求めるメジャーをChatGPTに聞いて完成させ、その後に複数データ対応版をChatGPTに聞いて作りました。

250619wma02

1) 温度データ
名称:'気温データ'
項目:[日付]、[地点]、[温度]

※ 1地点のメジャーは下記を使用しています。
名称:'_気温データ'
項目:[日付]、[温度]


2) カレンダ
名称:'カレンダ'
項目:[日付]

補足:[地点]が1つならカレンダは不要だが、[地点]が複数ある場合は、カレンダを分けたほうがメジャー式が複雑にならない。
理由:移動平均は時間軸方向の複数のデータを計算対象にするので、日付のフィルタを解除する必要があるが、カレンダが分かれているとカレンダのみフィルタが開場され、他の項目は開場されないので式、フィルタを掛け直す式が不要になる。


3) 区間
名称:'区間'
項目:[平均区間]

平均する区間の日数をDAX式で参照できるようにするため、表にしてデータモデルに追加します。これをスライサーで切り替えることもできます。


4) リレーション
'カレンダ'[日付] 1-->--* '気温データ'[日付]:多地点用
'カレンダ'[日付] 1-->--* '_気温データ'[日付]:1地点用

5) 加重移動平均1のメジャーDAX式([地点]が1つの時)

M加重移動平均1:=
VAR Interval = MAX('区間'[平均区間]) // 平均区間日数
VAR CurrentDate = MAX('カレンダ'[日付]) // 移動平均を求める日
VAR TargetDates = // 移動平均する日付の表
    FILTER(
        ALL('カレンダ'), // ピボットテーブルのフィルタコンテキストを解除し、全部の日付を参照できるようにする
        'カレンダ'[日付] <= CurrentDate && // 移動平均を求める日以前
        'カレンダ'[日付] > CurrentDate - Interval // 移動平均を求める日 - 平均区間日数以降
    )
VAR TempTable = // 加重移動平均を求める温度と重みの表
    ADDCOLUMNS(
        FILTER(
            ALL('_気温データ'), // ピボットテーブルのフィルターコンテキストを解除し、全部の気温データを参照できるようにする
            '_気温データ'[日付] IN // IN いずれかと一致する
                SELECTCOLUMNS(TargetDates, "TargetDate", [日付]) // 移動平均する日付の表から[日付]列のみ抜き出す
        ),
        "Weight", RANKX( // 移動平均する日付の表で[日付]の順位を昇順で求める。一番古日付が1位=重みが1になる
            TargetDates, // 評価する表=移動平均する日付の表
            [日付], // 順位を決める項目
            ,
            ASC // 昇順(小さい順、小さい日付=古い日付が1位)
        )
    )
VAR WeightedSum = SUMX(TempTable, [気温] * [Weight]) // 加重した温度の合計
VAR WeightSum = SUMX(TempTable, [Weight]) // 加重した温度の数
RETURN // 加重した温度の合計 / 加重した温度の数 = 各地点の加重移動平均温度
    IF(WeightSum > 0, WeightedSum / WeightSum, BLANK())

6) 加重移動平均2のメジャーDAX式([地点]が複数の時)

各地点の温度を平均し、それの加重移動平均を計算する式です。ピボットテーブルのフィルタコンテキストを利用するので、地点のフィルタ式が不要です。

M加重移動平均2:=
VAR Interval = MAX('区間'[平均区間]) // 平均区間日数
VAR CurrentDate = MAX('カレンダ'[日付]) // 移動平均を求める日
VAR TargetDates = // 移動平均する日付の表
    FILTER(
        ALL('カレンダ'[日付]), // ピボットテーブルのフィルタコンテキストを解除し、全部の日付を参照できるようにする
        'カレンダ'[日付] <= CurrentDate && // 移動平均を求める日以前
        'カレンダ'[日付] > CurrentDate - Interval // 移動平均を求める日 - 平均区間日数以降
    )
VAR AvgTempTable = // 加重移動平均を求める温度の表
    ADDCOLUMNS(
        TargetDates, // 移動平均する日付の表に
        "AvgTemp", // 平均温度の列を追加する。
        CALCULATE(
            AVERAGE('気温データ'[気温]), // 平均温度を計算する
            '気温データ'[日付] = EARLIER([日付]) // 同じ日の各地点の温度を平均する
            // EARLIER()は、CALCULATEの外のTargetDatesの"日付"列を参照する
        )
    )
VAR WeightedTable = // 加重移動平均を求める温度と重みの表
    ADDCOLUMNS(
        AvgTempTable,
        "Weight", RANKX(AvgTempTable, [日付], , ASC) // 移動平均する表で[日付]の順位を昇順で求める。一番古日付が1位=重みが1になる
    )
VAR WeightedSum = SUMX(WeightedTable, [AvgTemp] * [Weight]) // 加重した温度の合計
VAR WeightSum = SUMX(WeightedTable, [Weight]) // 加重した温度の数
// 加重した温度の合計 / 加重した温度の数 = 各地点の加重移動平均温度
RETURN DIVIDE(WeightedSum, WeightSum)

※ AvgTempTable と WeightedTableは、まとめても良いと思います。


7) 参考:'気温データ'[日付] = EARLIER([日付]) の可読性向上

EARLIER([日付])が何を指しているのかを確認する質問をChatGPTにしたところ、次のコード提案がありました。

EARLIER() はやや分かりにくいので、次のように VAR を使って明示する方法もおすすめです:

VAR AvgTempTable =
    ADDCOLUMNS(
    TargetDates,
    "AvgTemp",
    VAR ThisDate = [日付] // [日付]はTargetDatesの"日付"列
    RETURN
        CALCULATE( // [日付]はTargetDatesの"日付"列に等しい気温の平均を計算する
            AVERAGE('気温データ'[気温]),
            '気温データ'[日付] = ThisDate // ThisDateは、TargetDatesの"日付"列
        )
    )

8) 加重移動平均3のメジャーDAX式([地点]が複数の時)

各地点の加重移動平均を求めてから、それを平均します。各地点ごとに加重移動平均を計算するために、'気温データ'のコンテキストフィルタを解除すると、複数の地点が含まれた'気温データ'になるので、地点のフィルタ式が必要です。

M加重移動平均3:=
VAR Interval = MAX('区間'[平均区間]) // 平均区間日数
VAR CurrentDate = MAX('カレンダ'[日付]) // 移動平均を求める日
VAR TargetDates = // 移動平均する[日付]列
    SELECTCOLUMNS(
        FILTER(
            ALL('カレンダ'), // ピボットテーブルのフィルタコンテキストを解除し、全部の日付を参照できるようにする
                'カレンダ'[日付] <= CurrentDate && // 移動平均を求める日以前
                'カレンダ'[日付] > CurrentDate - Interval // 移動平均を求める日 - 平均区間日数以降
        ),
        "日付", 'カレンダ'[日付] // 列名を"日付"、データを[日付]のみにする
    )
VAR PlaceList =
    VALUES('気温データ'[地点]) // フィルターコンテキスト内の地点一覧
VAR Result =
    AVERAGEX( // フィルタコンテキスト各地点の加重移動平均の平均
        PlaceList, // フィルタコンテキスト各地点
        VAR ThisPlace = [地点] // PlaceListの行コンテキストの[地点]
        VAR TempTable = // 移動平均を出す日付と地点と気温と重みの表
            ADDCOLUMNS( // 重みの列を追加
                FILTER(
                    ALL('気温データ'), // ピボットテーブルのフィルタコンテキストを解除し、全部の気温データを参照できるようにする
                    '気温データ'[日付] IN TargetDates && // 移動平均する日付で絞り込み
                    '気温データ'[地点] = ThisPlace // 地点で絞り込み
                ),
                "Weight", RANKX(TargetDates, [日付], , ASC) // 移動平均する日付の表で[日付]の順位を昇順で求める。一番古い日付が1位=重みが1になる。
            )
        VAR WeightedSum = SUMX(TempTable, [気温] * [Weight]) // 加重した温度の合計
        VAR WeightSum = SUMX(TempTable, [Weight]) // 加重した温度の数
        RETURN DIVIDE(WeightedSum, WeightSum) // 加重した温度の合計 / 加重した温度の数 = 各地点の加重移動平均温度
    )
RETURN Result


9) 参考:VAR ThisPlace = [地点]の可読性の向上

次の式の[地点]が何を指すのか分かりにくいと思います。
VAR ThisPlace = [地点] // PlaceListの行コンテキストの[地点]

そこで、ChatGPTに質問したところ、次の回答を得ました。

DAX の可読性と確実性を上げるには、以下のように SELECTCOLUMNS で列名を付けてから、[ThisPlace] のように明示的に参照するのがよいです。

VAR PlaceList =
    SELECTCOLUMNS(
        VALUES('気温データ'[地点]),
        "ThisPlace", '気温データ'[地点] // "地点"ではなく"ThisPlace"として区別しやすくする
    )
VAR Result =
    AVERAGEX(
        PlaceList,
        VAR ThisPlace = [ThisPlace] // ThisPlaceの[ThisPlace]であることが分かりやすい
        VAR TempTable =
            ADDCOLUMNS(
                FILTER(
                    ALL('気温データ'),
                    '気温データ'[日付] IN TargetDates &&
                    '気温データ'[地点] = ThisPlace
                ),
                "Weight", RANKX(TargetDates, [日付], , ASC)
            )
        VAR WeightedSum = SUMX(TempTable, [気温] * [Weight])
        VAR WeightSum = SUMX(TempTable, [Weight])
        RETURN DIVIDE(WeightedSum, WeightSum)
    )

3. ChatGPTの活用

ChatGPTに単純にインプットとアウトプットを示して、そのアウトプットを得るメジャーを質問しても、1回で正解を得ることはできません。
この時、単純にエラーメッセージを伝えて改善する場合もありますが、正解にたどり着けなかったり、正解が出ても非合理的な式になることがあります。
なので、自分でエラーの原因を調べ、1) 正確なエラーメッセージ、2) 自分が推定した原因、3) 自分が考えた対策の方向、を示すと効率的に正解が得られます。


本記事のChatGPTの利用経緯

最初、カレンダテーブルを使うことを条件にして、YouTubeのワークシート式をメジャーにすることを依頼しました。最初Power BIでしか使えない関数や、VARに日本語が使われましたが、その指摘をすること他でM加重平均1が求まりました。なお、RANKX()を用いて重みを求める方法は、ChatGPTが最初に提案してくれました。

次に多地点対応のメジャーを依頼しました。エラーや可読性の悪さを指摘して完成したのが、M加重移動平均3です。

このメジャーの地点のフィルタ式を無くしたいと思い、地点マスターテーブルや、ALL()の解除列制限などを提案しましたが、そのような解は得られませんでした。
そこで、各地点の各日付の気温の平均を先に計算して、地点フィルタを削除して欲しいと指示したところ、M加重移動平均2の回答を得られました。

加重移動平均2は、ピボットテーブルのフィルタコンテキストを活用して、地点のフィルタ式がないシンプルな式になっていますが、これはその指示を与えた結果得られた式です。

なお、途中で意味が不明な点を質問しながら作ったので、ChatGPTが意味を明確にするために多少冗長な回答を生成しています。

4. サンプル

ダウンロード - 250619wma.xlsx

 

5. 比率の移動平均

比率の移動平均を求めるためには、比率を求めるための分母と分子のそれぞれの移動平均を求めてから、比率を計算します。比率からExcelの分析ツールの移動平均やDAXのMOVINGAVERAGE関数で移動平均を求めてはいけません。

MOVINGAVAREGE
https://learn.microsoft.com/ja-jp/dax/movingaverage-function-dax
Power BIで使えます。Excelでは使えません。

6. 関連記事

累計メジャーDAXの勘違い(歯抜け) : 当ブログ : 2025/01/27
https://bigarrow.tea-nifty.com/blog/2025/01/post-08315e.html
比率の移動平均を求める時は、累計のメジャーを利用して、分母と分子の区間合計を求めて、比率を計算することもできます。

Power BI質問コーナー ★時間別価格平均、5日移動平均★
https://www.youtube.com/watch?v=iybH-rHO2Uk&list=PLT57AeE7qQiPxZD4NxxzUPqXxn2Fk8qge&index=1


| | コメント (0)

Windows 11 Home をローカルアカウントでセットアップ:Shift+F10が無反応の場合

§ [2025/10/08]の情報:余談

Windows 11 Insider Programのβチャネル の情報です。

Windows 11のセットアップ時にユーザーフォルダー名を指定する機能がようやく導入へ
https://forest.watch.impress.co.jp/docs/news/2053094.html

Windows 11 Insider Programで初期設定時に「任意のユーザーフォルダー名」を付ける“裏技”が登場 ローカルアカウントでのセットアップから卒業できるか?
https://www.itmedia.co.jp/pcuser/articles/2510/07/news108.html

これがリリースされれば、わざわざローカルアカウントでセットアップしなくても良くなるのですが...25H2では、まだのようです。


§ [2025/06/20]の投稿:本題

Windows 11 のセットアップ時にマイクロソフトアカウントでセットアップすると、ユーザーフォルダ名がマイクロソフトアカウントの名前になります。
ユーザーフォルダ名をマイクロソフトアカウントとは異なる名前にする場合は、ローカルアカウントでセットアップをします。

注意:2025年6月20日時点の情報です。今後変わる可能性があります。

1. Windows 11をローカルアカウントでセットアップする手順

1) LANケーブルを外す。
2) AC電源を接続して、電源を入れる。
3) 言語を選択し[はい]。
4) 地域を選択し[はい]。
5) キーボード[Microsoft IME]を選択し[はい]。
6) 2つ目のキーボードのレイアウト設定を[スキップ]。

7) WiFiの接続画面が出ますが、[接続]を押さないでおきます。

この状態で[Shift]+[F10]を押してコマンドプロンプトを開きます。
ASUSやDELのノートPCでは、Fnキーがロックされていることがあるので、[Fn]+[Esc]でFnキーロックを解除してから[Shift]+[F10]を押します。

参考:Windows11 Home ローカルアカウントセットアップ
https://e-wiseweb.com/blog/21.html

8) コマンドプロンプトに「start ms-cxh:localonly」と入力し[Enter]。

参考:

俺はローカルアカウントで使いたいんだよ!Windows 11のセットアップでMicrosoftアカウントを回避する方法最新版
https://pc.watch.impress.co.jp/docs/topic/feature/2036750.html

ローカルアカウントでWindows 11をセットアップする方法【令和7年最新版】
https://forest.watch.impress.co.jp/docs/serial/yajiuma/2002656.html

9) ユーザー名にユーザーフォルダ名を入力し[次へ](パスワードの設定は必須ではないです。)
※ ユーザー名は、半角英数字が良いです。全角などを使用すると、海外アプリで不都合が出る場合があります。

10) ASUSやHPのノートPCではASUSやHPのユーザー登録画面が出ますが、何も入力しないで[次へ]。(ユーザー登録は、後でもできます。)

11) 位置情報の送信などの設定を画面に従って進めるとWindowsのセットアップが完了します。

以上でマイクロソフトアカウントではないローカルアカウントのユーザー名のユーザーフォルダが作成されます。

12) [設定]の[アカウント]からマイクロソフトアカウントに切り替えます。ユーザーフォルダ名は、ローカルアカウント名のまま使用します。

※ OneDriveの同期やバックアップをしたくない場合は、マイクロソフトアカウントでWindowsにサインインする前にOneDriveをアンインストールしてください。アンインストールせずにOneDriveを終了してタスクマネージャーのスタートアップで無効にしても良いですが、自動復活に注意が必要です。
スマホのように、PCの故障に備えてクラウドへのバックアップを利用したい人は、アンインストールせずにOneDriveを利用してください。
意味が分からないが、将来(5GB越えで)OneDriveに絶対課金したくない人は、アンインストールしたほうが良いかも知れません。(OneDriveをアンインストールしても、バックアップや同期をしないだけで、ブラウザからOneDriveを利用できます。)

※ Windowsをローカルアカウントで使用する場合でも、一度マイクロソフトアカウントでWindowsにサインインしてから、ローカルアカウントに戻す方が良いです。理由は、ハードウェアの変更でWindowsの再認証が必要になった場合、マイクロソフトアカウントで再認証できるらしいからです。

※ プリインストールのOfficeなどをセットアップする場合は、その前にWindowsをマイクロソフトアカウントでサインインしたほうが混乱しにくいかも知れません。特典でMicrosoftのゲームパックなどが付いているPCも同様です。(もし、Windowsにローカルアカウントでサインインしたままでマイクロソフトのプリインストール版をマイクロソフトアカウントに登録する場合は、Microsoft Storeにライセンスを登録するマイクロソフトアカウントでサインインしてください。)

2. 参考情報

3. 色々なサービスへのサインイン

Windowsのサインインのアカウント(ローカルアカウント含む)と、Officeほかのサービスを使うためのMicrosoftアカウントは別々に設定できます。例えば、Windowsに個人のMicrosoftアカウントでサインインし、Officeに学校のマイクロソフトアカウントでサインインしても使用することは可能です。

WindowsにAのMicrosoftアカウントでサインインしている場合、Microsoft StoreはAのアカウントでサインインされるようです。その場合でも、Microsoft StoreをBのMicrosoftアカウントに切り替えることはできそうです。

既にそのPCで各サービスにサインしていて、他のマイクロソフトアカウントでサインインしたい場合は、一旦そのサービスからサインアウトしてください。Microsoft365の各サービス(Outlook、OneDrive、Office、Teamsなど)のサインインは、Microsoft365で共通です。

■ Edge
Edgeを起動し、右上の人型アイコンからサインイン
注意:他のPCと同期します。

■ Outlook (Microsoft 365)
Microsoft Outlook へようこそ : Microsoft 365
https://www.microsoft.com/ja-jp/microsoft-365/outlook/log-in

■ OneDrive (Microsoft 365)
Microsoft OneDrive : Microsoft 365
https://www.microsoft.com/ja-jp/microsoft-365/onedrive/online-cloud-storage

注意:OneDriveアプリの場合は、設定により他のPCと同期します。

■ Microsoft365/Officeアプリ (Microsoft 365)
Officeアプリを起動し、右上の丸いアカウントのアイコンで、サインアウト後、希望のマイクロソフトアカウントでサインイン。

■ Microsoft365/Office Web (Microsoft 365)
Microsoft 365 または Office にサインインする方法 : Microsoft Support
https://support.microsoft.com/ja-jp/office/-b9582171-fd1f-4284-9846-bdd72bb28426#id0ebbl=web

■ Microsoft365/Office Online(Web) 無料版 (Microsoft 365)
Web 用 Microsoft 365 アプリを無料で使用 : Microsoft 365
https://www.microsoft.com/ja-jp/microsoft-365/free-office-online-for-the-web

■ マイクロソフトアカウント
Microsoft アカウントにサインインする方法 : Microsoft Support
https://support.microsoft.com/ja-jp/account-billing/-2ffedaca-6e1b-bc18-f28c-58539e1cb6d3

■ Microsoft Store
メニューからMicrosoft Storeを起動し、右上の人型アイコンからサインイン

■ Windowsのサインインの切り替え
Windows でローカル アカウントから Microsoft アカウントに変更する : Microsoft Support
https://support.microsoft.com/ja-jp/windows/-395203bf-9f1b-eb24-b042-5b8dae6c1d20
注意:設定により他のPCと同期します。

| | コメント (0)

Excelの物の入出簿で在庫管理をする式の検討

はじめに

Yahoo!知恵袋に次のような質問がありました。
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q14316173369
追加削除履歴があり、それを日別の在庫リストにするイメージです。
在庫リストは品種と数のクロス表ではなく、存在する品種の在庫をリストに列挙する形になっています。

ピボットテーブルではこの形の表を作成することができず、複雑なワークシート式やPower Query Mコードが必要になったので、備忘録として式やコードの仕組みをメモしておきます。

質問では追加削除履歴の削除が翌日の在庫に反映するようになっていますが、本例では一般的な当日の在庫に反映させています。(削除を翌日に反映するには、+1日した日付列をPower Queryで追加します。)

本例の集計表は一般的ではないです。一般的なPSI管理表をご希望の方は、次の記事を見てください。

1. 入力表

入力表は追加削除した種類を記入した入出簿です。数の情報はありません。
250616iridebo01

2. 出力表

1) 在庫を数字で表した表です。3.に集計方法を示します。

250616iridebo03

2) 在庫の種類を在庫数量分繰り返し列挙したものです。(Yahoo!知恵袋の質問の要求事項です。) 4~6.に集計方法を示します。

250616iridebo02

3. 在庫を数で集計する手順

これは簡単です。前記1)の出力であれば、式はメジャーの1つのみです。その他は殆どクリック操作で作成することができます。

1) 入力ブックの取得:集計ブックを開き[データ]-[データの取得v]-[ファイルから>]-[エクセルブックから]で入力表のブックを選択し[インポート]で入力表のシートを選択し[データの変換]でPower Queryに取得します。右ペインのクエルの設定のプロパティの名前を"入出簿"に変更します。
2) 自動挿入された不要なステップを削除:適用したステップの"ナビゲーション"より下のステップの左の×をクリックして、削除します。
3) ヘッダーの設定:[変換]-[1行目をヘッダとして設定v]-[1行目をヘッダとして設定]。
4) 省略されている日付を埋める:"日付"列を選択し[変換]-[フィルv]-[下へ]。
5) 型の設定:Ctrl+aで全列を選択し[変換]-[データ型の検出]。データ型が正しくなければ、個々に修正。

6) 追加クエリの作成:左の"入出簿"クエリを右クリックし[参照]。右の名前を"追加"に変更。
7) 不要な列を消す:Ctrlを押しながら"日付"と"追加"列を選択し[ホーム]-[列の削除v]-[他の列の削除]。
8) データが無い不要な行を削除:"追加"列の右の▼をクリックし[空の削除]。
9) 増減数の列を追加:[列の追加]-[カスタム列]で次のように入力

新しい列名:数
カスタム列の式:= 1

10) 列名を変更:"追加"列をWクリックし、名前を"種類"に変更。

11) 削除クエリの作成:左の"入出簿"クエリを右クリックし[参照]。右の名前を"削除"に変更。
12) 不要な列を消す:Ctrlを押しながら"日付"と"削除"列を選択し[ホーム]-[列の削除v]-[他の列の削除]。
13) データが無い不要な行を削除:"削除"列の右の▼をクリックし[空の削除]。
14) 増減数の列を追加:[列の追加]-[カスタム列]で次のように入力

新しい列名:数
カスタム列の式:= -1

15) 列名を変更:"削除"列をWクリックし、名前を"種類"に変更。

16) 集計クエリの作成:[ホーム]-[クエリの追加v]-[クエリを新規クエリとして追加]で、最初のテーブルに[追加]、2つ目のテーブルに[削除]を選択し[OK]。右の名前を"集計"に変更する。
17) 型の変更:"日付"列を選択し[変換]-[データ型]-[日付]。"数"列を選択し[変換]-[データ型]-[整数]。

18) カレンダテーブルの作成:左の"集計"クエリを右クリックし[参照]。右の名前を"カレンダ"に変更。
19) 日付列のみにする:"日付"列を選択し[ホーム]-[列の削除v]-[列の削除]。
20) 日付の重複を削除:"日付"列を選択し[ホーム]-[行の削除v]-[重複の削除]。

21) Excelに戻る:[ホーム]-[閉じて読み込むv]-[閉じて次に読み込む]で"接続の作成のみ"を選択し[OK]でExcelに戻る。

22) カレンダをデータモデルに追加する:右のクエリと接続ペインの"カレンダ"クエリを右クリックし[接続先]で"データモデルに追加する"をチェックし[OK]。(クエリを接続が表示されていない時は、[データ]-[クエリと接続]をクリックする)
23) 集計をデータモデルに追加しピボットテーブルに読み出す:右のクエリと接続ペインの"集計"クエリを右クリックし[接続先]で"ピボットテーブル"と"データモデルに追加する"をチェックし[OK]。

24) リレーション:[データ]-[データモデル(緑アイコン)v]-[リレーションシップ]-[追加]で次のように設定。
テーブル:集計。関連テーブル:カレンダ。列と関連列:日付。

[Power Pivot]-[管理]-[ダイヤグラムビュー]で'集計'[日付]を'カレンダ'[日付]にドラッグしても良い。

25) メジャーの作成:ピボットテーブルをクリックし、右のピボットテーブルのフィールドで'集計'を右クリックし[メジャーの追加]で次のように入力し[OK]。

メジャーの名前:M在庫
数式:
=VAR n = CALCULATE( // 累計を求めるメジャー
    SUM('集計'[数]), // 追加削除数を合計する
    FILTER(ALL('カレンダ'), 'カレンダ'[日付] <= MAX('カレンダ'[日付])) // 累計範囲のフィルタ
  )
RETURN // 値がある時のみ値を返す。値が無ければnullとなる。
  IF(n<>0, n)

カテゴリ:数値。書式:10進数。小数点以下の桁数:0。桁区切り(,)を使う:チェック。

26) ピボットテーブルの設定:ピボットテーブルをクリックし、右のピボットテーブルのフィールドで[すべて]をクリックし、次のように設定。

列:'カレンダ'[日付]。行:'集計'[種類]。Σ値:[M在庫]。

4. '集計'クエリから在庫の種類を日別に列挙する手順

例えば在庫の種類が緑で在庫数が2の1行を、緑、緑にすると行が2行になります。しかし、メジャーで項目は生成できないので、メジャーではこの処理ができません。そこで、ワークシート関数でこの処理を行います。

27) 26)で作成したピボットテーブルのシートをコピーし、ピボットテーブルのフィールドの展開を次のように変更する。

列:無し。行:'カレンダ'[日付]、'集計'[種類]。Σ値:[M在庫]。

28) セルレイアウトの設定:ピボットテーブルを左上の"日付"がA2セルになる位置に移動。セルE3から横に抽出する日付を日付形式で入力。

250617iridebo05

29) 集計式の入力:セルE4に次の式を入力

=LET(
  日付, E3,
  種類, FILTER($B:$B, $A:$A=日付),
  累計, FILTER($C:$C, $A:$A=日付),
  n, SUM(累計),
  seq, SEQUENCE(n),
  idx, XMATCH(seq, SCAN(0,累計,LAMBDA(a,b,a+b)),1),
  INDEX(種類, idx)
)

【式の解説】9/4を例にする
=LET(
  日付, E3, // 抽出する日付 = 9/4
  種類, FILTER($B:$B, $A:$A=日付), // 抽出する日付の種類の配列 = {黄,緑}
  在庫, FILTER($C:$C, $A:$A=日付), // 抽出する日付の在庫数の配列 = {1, 2}
  n, SUM(在庫), // 在庫の合計=抽出する行数 = 1+2 = 3
  seq, SEQUENCE(n), // 抽出先の行の行番号 = {1, 2, 3}

  idx, XMATCH(seq, SCAN(0, 在庫, LAMBDA(a, b, a+b)), 1),
  // SCAN(初期値, 配列, LAMBDA(累積値, 現在値, 計算式))。累積値=アキュムレータ
  // SCAN(0, 在庫, LAMBDA(a, b, a+b)):初期値=0 ⇒ 最初に累積値a=0になる。在庫の行毎に在庫の値がbに入り、a+bで累積値aが加算される。
  //   初期値 a=0、最初の値 b=1 ⇒ a+b=1 ⇒ a=1
  //   次:a=1, b=2 ⇒ a+b=3 ⇒ a=3
  //   SCAN = {1, 3}
  // XMATCH(検索値, 検索範囲, 一致モード1=指定した値を越えない)⇒検索範囲で条件を満たす行番号を返す
  // XMATCH({1, 2, 3}, {1, 3}, 1) ⇒ {1, 2, 2}
  //   検索値1 は 検索範囲の値1以下 ⇒ 検索範囲の1行目 ⇒ 1
  //   検索値2 は 検索範囲の値3以下 ⇒ 検索範囲の2行目 ⇒ 2
  //   検索値3 は 検索範囲の値3以下 ⇒ 検索範囲の2行目 ⇒ 2
  // idx:各抽出先の行が対応する、元の抽出種類の行番号 = {1, 2, 2}

  INDEX(種類, idx) // INDEX({黄, 緑}, {1, 2, 2}) = {黄, 緑, 緑}
)

※ 解説を//で記載してますが、Excelのワークシート式に//でコメントを書くことはできません。

5. Power Queryで種類を在庫数分縦に並べる

メジャーでは項目の生成ができないので、PowerQueryで累計し、複数行に展開します。
このクエリはクリックでは生成できないので、"追加"と"削除"クエリを引き継いで、手動でコーディングします。
ポイントは次の2点です。

a) Power Queryで抜けの無い表を作成し累計列を追加する。
b) List.Repeat()関数を使用して、2個以上の種類の行を増やす。

16) 履歴クエリの作成:[データ]-[クエリと接続]でクエリをWクリックしてPower Queryエディタを開き、[ホーム]-[クエリの追加v]-[クエリを新規クエリとして追加]で、最初のテーブルに[追加]、2つ目のテーブルに[削除]を選択し[OK]。右の名前を"履歴"に変更する。

17) 日付でソート:"日付"列の▼をクリックし、[昇順で並び替え]。

18) M言語のコードを記述:[ホーム]-[詳細エディタ]で以下の処理コードを記述する。(最初のソースと並び替えられた行がクリックで生成したコード)

let
  ソース = Table.Combine({追加, 削除}),
  並べ替えられた行 = Table.Sort(ソース,{{"日付", Order.Ascending}}),

  // ここから下が直接記述するMのコード
  // 重複を除いた全種類と全日付を抽出
  種類一覧 = Table.Distinct(Table.SelectColumns(並べ替えられた行, {"種類"})),
  日付一覧 = Table.Distinct(Table.SelectColumns(並べ替えられた行, {"日付"})),

  // 日付×種類の全組合せを作成:種類一覧の各行に日付一覧を追加し、日付一覧を展開することで生成する
  種類に日付追加 = Table.AddColumn(種類一覧, "日付", each 日付一覧),
  展開 = Table.ExpandTableColumn(種類に日付追加, "日付", {"日付"}),
  // 追加削除の無い日の累計も計算するため、全組合せのテーブルを作成し、そのテーブルに累積列を追加する。

  // 種類ごとの日付順テーブルに対して、追加削除の数を累計して"累計数量"列に代入する。(r) => ... は行ごとの関数(ラムダ関数)
  累積追加 = Table.AddColumn(展開, "累積数量", (r) =>
    List.Sum( // [数]を合計(累計)
    // 「入出履歴(AddedQty)」テーブルから、条件に一致する行だけを抽出。[数]列のみ抽出。
      Table.SelectRows(並べ替えられた行, each [種類] = r[種類] and [日付] <= r[日付])[数]
    )
  ),

  // 0 より大きい場合のみ残す。累計を格納したので、在庫が無いデータは不要になり、削除する。
  抽出 = Table.SelectRows(累積追加, each [累積数量] > 0),

  // List.Repeat を使って、その在庫数分だけ「種類」を繰り返すリストを追加し、追加したリストを展開することで行を追加する。
  // 文法:List.Repeat(list as list, count as number) as list:
  // 元のリスト list を count の回数繰り返した結果のリストを返します。例:List.Repeat({1, 2}, 3)
  繰り返し列 = Table.AddColumn(抽出, "リスト", each List.Repeat({[種類]}, [累積数量])),
  展開済み = Table.ExpandListColumn(繰り返し列, "リスト"),

  // 最終出力整形
  結果 = Table.SelectColumns(展開済み, {"日付", "リスト"}), // [日付]と[リスト]列のみにする
  変更された型 = Table.TransformColumnTypes(結果,{{"日付", type date}, {"リスト", type text}}),
  並べ替えられた行1 = Table.Sort(変更された型,{{"日付", Order.Ascending}, {"リスト", Order.Ascending}})
in
  並べ替えられた行1

19) テーブルへの読み出し:[ホーム]-[閉じて読み込むv]-[閉じて次に読み込む]で"テーブル"を選択し[OK]。


20) セルレイアウトの設定:テーブルを左上の"日付"がA2セルになる位置に移動。セルD2から横に抽出する日付を日付形式で入力。

250617iridebo06

21) 集計式の入力:セルD3に次の式を入力

=FILTER($B:$B, $A:$A = D$2)

6. ワークシート関数のみで種類を在庫数分縦に並べる

Yahoo!知恵袋に他の人が回答した式です。

1) セルレイアウトの設定:追加削除表の左上の"日付"がA1セル、作業用の追加削除表の左上の日付がI1セル、セルL2から横に抽出する日付を日付形式で入力、L2から横に中間式を入力、L3から横に検索結果の式を入力。

250617iridebo07

2) 作業用の追加削除表:セルI2に次の式を入力(この式はYahoo!知恵袋の回答にはありません。)

=LET(a,
  VSTACK(
    HSTACK($A2:$B8, TOCOL(
      TEXTSPLIT(
        REPT("追加,", ROWS($A2:$A8)),
        ",")
      )
    ),
    HSTACK($A2:$A8, $C2:$C8, TOCOL(
      TEXTSPLIT(
        REPT("削除,", ROWS($A2:$A8)),
        ",")
      )
    )
  ),
  FILTER(a, NOT(ISBLANK(CHOOSECOLS(a, 2))) * NOT(ISERROR(CHOOSECOLS(a, 2))))
)

【式の解説】
=LET(a,
  VSTACK( // "追加行の表"と"削除行の表"を縦に連結
    HSTACK($A2:$B8, // "日付と追加"列の表と"操作"列を横に結合する
      TOCOL( // 縦にする⇒操作列になる
        TEXTSPLIT( // ","で配列に分割する
          REPT("追加,", ROWS($A2:$A8)), // "追加,"を行数分結合する
          ",")
      )
    ),
    HSTACK($A2:$A8, $C2:$C8, // "日付"と"削除"と"操作"列を横に結合する
      TOCOL( // 縦にする⇒操作列になる
        TEXTSPLIT( // ","で配列に分割する
          REPT("削除,", ROWS($A2:$A8)), // "削除,"を行数分結合する
          ",")
      )
    )
  ),
  // 2列目("種類"列)が空欄(データが無い)ではない行と
  // エラー(REPTで生成する操作列の最後に","が付くので、操作列が1行多くエラーになる)ではない行を取得する
  FILTER(a, NOT(ISBLANK(CHOOSECOLS(a, 2))) * NOT(ISERROR(CHOOSECOLS(a, 2))))
)

3) 作業用の種類文字列:セルL2に次の式を入力

=LET(
  fx_1, LAMBDA(項目, FILTER($J:$J, ($I:$I<=L1) * ($K:$K=項目), "")),
  追加, TEXTJOIN(",", , fx_1("追加")),
  削除, fx_1("削除"),
  fx_2, LAMBDA(fx_2,リスト,i,
    IF(i <= COUNTA(削除),
      fx_2(fx_2, SUBSTITUTE(リスト, INDEX(削除, i), "", 1), i+1),
      リスト)
  ),
  fx_2(fx_2, 追加, 1)
)

【式の解説】

L1=9/3の時のデータフィルタリング結果
追加データ
日付,種類,操作
9/1,赤,追加
9/1,緑,追加
9/2,黄,追加
9/2,白,追加
9/3,黒,追加

削除データ
日付,種類,操作
9/3,白,削除
9/3,赤,削除

=LET(
  // 種類列($J:$J)を、日付列($I:$I)<=検索日付(L1)と操作列($K:$K)=項目(追加/削除)で、フィルタする
  fx_1, LAMBDA(項目, FILTER($J:$J, ($I:$I<=L1) * ($K:$K=項目), "")),
  追加, TEXTJOIN(",", , fx_1("追加")), // 操作が追加の種類を","区切りで結合する⇒"赤,緑,黄,白,黒"
  削除, fx_1("削除"), // 操作が削除の種類を配列にする⇒{白, 赤}

  // 削除の各要素を追加文字列から1つずつ消していく再帰関数
  fx_2, LAMBDA(fx_2,リスト,i,
    IF(i <= COUNTA(削除), // 削除の行数を越えたら再帰終了=削除の行分繰り返す
      fx_2(fx_2, SUBSTITUTE(リスト, INDEX(削除, i), "", 1), i+1),
      リスト)
  ),

  fx_2(fx_2, 追加, 1) // 最初に呼び出す際の引数(自身(再帰の為), 追加文字列, インデックス1)
  // 初期値:
  //   リスト = "赤,緑,黄,白,黒"
  //   i = 1
  //   削除 = {"白", "赤"}
  // ステップ 1: i = 1
  //   INDEX(削除,1) = "白"
  //   SUBSTITUTE("赤,緑,黄,白,黒", "白", "", 1) で削除の1行目の白を""に置換 → "赤,緑,黄,,黒"
  //   再帰呼出し → fx_2(fx_2, "赤,緑,黄,,黒", 2)
  // ステップ 2: i = 2
  //   INDEX(削除,2) = "赤"
  //   SUBSTITUTE("赤,緑,黄,,黒", "赤", "", 1) で削除の2行目の赤を""に置換 → ",緑,黄,,黒"
  //   再帰呼出し → fx_2(fx_2, ",緑,黄,,黒", 3)
  // ステップ 3: i = 3
  //   i > COUNTA(削除)なので再帰終了、リストを返す
  // → 結果:,緑,黄,,黒
)

補足:なぜ fx_2 を自分自身に渡す必要があるのか?

Excel の LETで変数に定義したLAMBDAでは、関数定義内から「自分自身」を直接参照できません。
再帰を実現するには、第1引数として「自分自身」を渡す必要があります。
なお、名前の定義でLAMBDAを使用した場合は、グローバル名空間の名前になるので、自身の引数が無くても再帰呼出しができます。

4) 種類の抽出結果:セルL3に次の式を入力

=TEXTSPLIT(L2, , ",", TRUE)

【式の解説】

TEXTSPLITでカンマ区切りし、空文字を無視(第4引数がTRUE)
  L2 = ",緑,黄,,黒"
  結果:{緑, 黄, 黒}

7. サンプルファイル

ダウンロード - 250617iridebo.xlsx

C:\Users\Public\Documents に格納してください。  

8. 参考

長いワークシート関数式、配列数式を作る方法

| | コメント (0)

Excelで在庫管理/生産管理(メジャーで期間末在庫を算出)

はじめに

物品を扱う会社では、入荷・出荷・在庫の情報を管理するために、PSI(Production, Sales, Inventory)管理表を用います。

在庫は次の式で算出されます:在庫 = 前日の在庫 + 当日の入荷 − 当日の出荷。 または、在庫 = 入荷累計 - 出荷累計。

在庫管理システムを使うのが一般的だと思いますが、Excelで在庫管理を行う会社もあるようです。Excelの在庫管理表には週末や月末の合計、月別の表には四半期・半期・年間の合計が含まれることがあります。この在庫管理表から別の表を作る場合、小計により入力セルアドレスが連続ないので、オートフィルやスピルが使えず、セルアドレスを間違うことがあります。

そこで、間違いの元となるセルアドレスを使用しないメジャーで在庫や月次、四半期、年次の集計をしてみました。

注意:本記事の方法を使用する場合は、十分検証を行い、自己責任でお願いいたします。

参考:メジャーとは

参考:シンプル版を作成しました。[2026/08/05]

1. Excelの問題

1) コピペや参照ミスのリスク:

日別の表から月別の表をコピー&ペーストやセル参照式で作成すると、参照アドレスのズレや貼り付けミスにより、集計結果に誤りが生じる恐れがあります。特に不連続な表は、間違いを起こしやすいです。
(行番号と列番号を使用するVBAにも同様のリスクがあります。但し、本記事のPower Queryでも、条件によりこのリスクが多少残ります。)

2) データの再利用性が低い:

入荷・出荷のデータは、売上金額、仕掛金額、市場クレーム率などの他の経営指標算出にも利用されます。途中に四半期合計などの小計が入っているとデータが不連続になり、再利用時に参照ミスが起こりやすくなります。
例:月ごとのデータをコピーした際、途中に小計が入り、月がずれてしまう。

3) 新しい品目の集計漏れ:

新しい商品が追加された場合、集計表にその項目の記入を忘れると、集計対象から漏れます。

2. 方針

ExcelのPower Query, Power Pivotを用いることで、1.の課題を解決し、ミスの原因となるセルアドレス参照式を削減します。式が少ないので可読性と保守性が向上します。

1) 入力ファイルと集計ファイルを分離し、Power Queryで入力ファイルを取得する:

PSIの入力ファイルを次のいずれかの構成にします。

a) 1ファイル1シート。b) 1ファイルに複数シート。c) 1フォルダに複数ファイル(各ファイルに1シート)。d) 1フォルダに複数ファイル(各ファイルに複数シート)。

本記事ではa) 1ファイル1シートの例を示します。
b)~d)にもPower Queryの処理手順を変えることで対応可能です。「5. 参考リンク」を見てください。

集計ファイルは、入力ファイルとは別のファイルにします。

2) 入力ファイルは「日々のデータ」のみとする:

合計行や小計行を挿入しないことで、連続データとし、データを再利用しやすくします。
※ 入力表にも合計や小計を入れて、Power Queryのフィルタでそれらを除去するステップを追加することもできます。

3) 管理用の閲覧・集計表をピボットテーブルで集計する:

集計や分析は、別のファイルでピボットテーブルを用いて行います。これにより、小計や合計の数式を削減し、数式の入力ミスを抑えます。

3. 手順

3-1. ブックの作成(Excel)

1) 入力表の作成:入力ブックにPSIの入力表を作成します。

本例では入荷と出荷のみ入力して集計表で在庫を計算する方法と、入力表に在庫も入力して入力表の在庫を集計する方法の2つを示します。
前者の方が式が簡単になります。
後者は在庫を求めるワークシート式が必要ですが、入力表で在庫が確認できるメリットがあります。

表の形は、1日単位で日を横に並べるクロス表と、縦に入出荷の履歴を並べる方法がありますが、本例では前者の手順を示します。
なお、データベースとしては、後者の方が使いやすく、整形ステップが少なくなります。なので、可能であれば、後者の方が良いです。
250616psi01 250616psi02

日付はシリアル値で入力します。(テキストで年月(yy/mm)を入れる場合は、カレンダテーブルにも同様に年月のテキスト列を設けます。)

参考 : '入荷'と'出荷'の元データが分かれている場合でも、Power Pivotで1つのピボットテーブルに集計することができます。入庫単価を用いて在庫金額、金額回転率、出庫金額を集計することもできます。
「5.参考リンク」の「入庫単価が変動する物の在庫金額と回転率 Excel Power Pivot」を見てください。

2) カレンダテーブル(日付テーブル)の作成:
カレンダブックに集計する範囲の全日を含む連続した日付の表を作成し、[挿入]-[テーブル]でテーブルにします。これに集計したい区間の列(例:年度や四半期)の列を追加します。[テーブルデザイン]でテーブル名を"Calendar"にします。

250616psi03

参考 :
a) カレンダテーブルを集計ブックに作成しても良いです。

b) Excelでカレンダテーブルを作らずに、Power Query M言語で取得するデータの範囲のカレンダテーブルを生成することもできます。

Excel Power Query Mでカレンダを作成し、メジャーで前の値との差を計算:
https://bigarrow.tea-nifty.com/blog/2025/06/post-b14054.html

c) カレンダテーブルを作る目的は、DAX式を簡単にするためです。DAXのタイムインテリジェンス関数が使用できるメリットもあります。

3-2. データの取得と整形(Power Query)

3) カレンダテーブルの取得:

  • 集計ブックを開き、[データ]-[データの取得v]-[ファイルから]-[Excelブックから]でカレンダブックを選択し、[インポート]で"Calendar"を選択し、[データの変換]でPower Queryエディタに取込みます。
  • 右のプロパティで名前を"Calendar"にします。
  • [ホーム]-[閉じて読み込むv]-[閉じて次に読み込む]で"接続の作成のみ"と"このデータをデータモデルに追加する"を選択し[OK]。

4) 入力表の取得:

  • 集計ブックで[データ]-[データの取得v]-[ファイルから]-[Excelブックから]で入力ブックを選択し、[インポート]で入力表のシートを選択し、[データの変換]でPower Queryエディタが開きます。
  • 右のプロパティで名前を"PSI入力"にします。

5) 自動生成された不要なステップの削除:

  • 右の"適用したステップ"の"変更された型"の左の×をクリックして削除します。

6) 不要な行の削除:

  • "Column3"列の右の▼をクリック、[テキストフィルタ]で次のように設定し、[OK]。

250616psi04 ※ 必要な行のみ残す条件にすることにより、元表のセルアドレスの変更に影響されないクエリにします。 

7) ヘッダの設定:

  • [変換]-[1行目をヘッダーとして使用v]-[1行目をヘッダーとして使用]。

8) 顧客と製品のnullを埋める:

  • Ctrlを押しながら"顧客"と"製品"列を選択し[フィルv]-[下へ]。

9) 日付をピボット解除:

  • Ctrlを押しながら"顧客"と"製品"と"項目"列を選択し[変換]-[列のピボット解除v]-[その他の列のピボット解除]。

10) 入荷、出荷、在庫をピボット:

  • "項目"列を選択し[変換]-[列のピボット]で"値列"に[数]、詳細オプションの"値の集計関数"に[合計]を選び[OK]。(同じ日の同じ製品の入出荷データが1つであることが条件です。複数ある場合は、集計方針の変更が必要です。)

250616psi05

11) 型の設定:

  • Ctrl+aで全列を選択し[変更]-[データ型の検出]。型が適切でなければ修正する。日付の型は時刻を入れずにCalendarと合わせてください。

12) ワークシートとデータモデルへ読み出し:

  • [ホーム]-[閉じて読み込むv]-[閉じて次に読み込む]で"ピボットテーブル"と"このモデルをデータモデルに追加する"を選び[OK]。

3-3. リレーション(Power Pivot)

集計にカレンダテーブルを使用できるようにするために、整形した入力表とカレンダテーブルを日付で関連付けします。

13)  [データ]-[データモデル(緑のアイコン)v]-[リレーションシップ]-[新規作成]でテーブルに"PSI入力"、関連テーブルに"Calendar"、列と関連列に"日付"を入力し[OK]。

250616psi06

または、[データ]-[データモデル(緑のアイコン)v]-[データモデルの管理]-[ホーム]-[表示v]-[ダイアグラムビューの表示]で'PSI入力'[日付]を'Calendar'[日付]にドラッグする。(Power Pivotのアドインが有効になるとメニューに[Power Pivot]が表示されるので、そこから[管理]でPower Pivot for Excelを起動できます。)

250616psi07

3-4. メジャー/DAX式で在庫計算(Power Pivot)

在庫のメジャーは、期の集計に期末在庫を表示する式にします。ワークシートの在庫を使うメジャー[M在庫w]と使わないメジャー[M在庫]の2つを紹介します。後者が一般的です。

ピボットテーブルを選択し、ピボットテーブルのフィールドの'PSI入力'を右クリックし[メジャーの追加]で次のように入力します。ここでは、ワークシートの在庫を使用するメジャーと、使用しないメジャーの2種類を紹介します。

参考 : 他のメジャー編集画面

[Power Pivot]-[管理]で表示されるPower Pivot for Excelのデータビューの数式バーで、メジャーを作成・編集することができます。数式バーはExcelと同様の方法で拡大することができます。数式を格納するセルは、最下部の任意のセルを選択します。数式バーには「メジャー名:=数式」という書式で書きます。

14) 在庫w:入力表で計算した在庫を使用する式(式が複雑なのと、ワークシート式を間違うと不整合になるので、一般的では無いです)

メジャーの名前:M在庫w
数式:
=VAR CalendarMax = MAX('Calendar'[日付]) // ピボットテーブルの最終日
VAR PSIDate =  // ピボットテーブルのフィルタコンテキスト内のPSI入力最終日
    CALCULATE(
      MAX('PSI入力'[日付]), // 'PSI入力'の最終日を求める
      FILTER(
        ALL('PSI入力'), // 'PSI入力'のコンテキストフィルタを解除
        'PSI入力'[日付] <= CalendarMax // 入力表の日付 <= ピボットテーブルの最終日
      )
    )
RETURN
  CALCULATE(
    SUM('PSI入力'[在庫]), // [在庫]を返す(1日1在庫データ前提[※])
    FILTER(
      ALL('PSI入力'[日付]), // 'PSI入力'のコンテキストフィルタを解除
      'PSI入力'[日付] = PSIDate // 'PSI入力'の最終日のみ抽出
    )
  )

カテゴリ:数値、書式:10進数、小数点以下の桁数:0、桁区切り(,)を使う

※ この式は入力表の1日に同じ顧客と製品のデータが1つのみであることが必要である。重複するとどちらか1つの在庫しかカウントされない。 

15) 在庫:入力表の累計入荷から累計出荷を引いて求める方法(入力表の在庫を使用しない方法)こちらが一般的です。

メジャーの名前:M在庫
数式:
=CALCULATE(
    SUM('PSI入力'[入荷]) - SUM('PSI入力'[出荷]),  // 入荷の累計 - 出荷の累計

    FILTER(
        ALL('Calendar'),
        'Calendar'[日付] <= MAX('Calendar'[日付]) // 累計を求めるフィルタ
    )

)

カテゴリ:数値、書式:10進数、小数点以下の桁数:0、桁区切り(,)を使う

※この式は入力表の1日に同じ顧客と製品のデータが複数あっても良い。但し、集計期間直前の在庫を直前の日の入荷に入れておく必要がある。

累計の仕組みは、次の記事を参照してください。

累計メジャーDAXの勘違い(歯抜け) : 当ブログ : 2025/01/27
https://bigarrow.tea-nifty.com/blog/2025/01/post-08315e.html


16) 在庫平均:M月回転率で使用する中間メジャーです。期間内の日々の在庫の平均値です。[2026/05/16追加]

メジャーの名前:M在庫平均
数式:
=AVERAGEX( // 在庫平均 = AVERAGE(日毎の(入荷累計 - 出荷累計))
    'Calendar',
    VAR CurrentDate = 'Calendar'[日付]
    RETURN
    CALCULATE( // 日毎の在庫 = 入荷累計 - 出荷累計
        SUM('PSI入力'[入荷]) - SUM('PSI入力'[出荷]),
        FILTER(
            ALL('Calendar'),
            'Calendar'[日付] <= CurrentDate
        )
    )
)

カテゴリ:数値、書式:10進数、小数点以下の桁数:0、桁区切り(,)を使う

式の解説

M在庫での累計計算では、「MAX('Calendar'[日付])」で累計範囲のフィルタを掛けていますが、これはコンテキストの最大の日付になります。これと同じ書き方をM在庫平均に適用すると、最大日の日付の在庫の平均=最大日の在庫になってしまいます。そこで、イテレータ関数AVERAGEXの行コンテキストが掛かる第2引数で関数を使用せずに「VAR CurrentDate = 'Calendar'[日付]」とすることで、行コンテキストの日付を取得し、その日以前までの累計を求めて平均しています。

17) 回転率:期間内の数量回転率です。期間が長いと大きくなります。[2026/05/16追加]

メジャーの名前:M回転率
数式:
=IF( // 期間回転数 = 期間出荷数合計 / 在庫平均。期間が長いと大きくなる。
    NOT(HASONEVALUE('Calendar'[日付])),
    DIVIDE(SUM('PSI入力'[出荷]), [M在庫平均])
)

カテゴリ:数値、書式:10進数、小数点以下の桁数:1、桁区切り(,)を使う

金額の回転率については、5.参考リンクの「入庫単価が変動する物の在庫金額と回転率 Excel Power Pivot」を見てください。

18) 月あたりの回転率: 月当たりの数量回転率です。[M在庫平均]を使用します。生産管理で使われるそうです。[2026/05/16訂正]

メジャーの名前:M月回転率
数式:
=VAR ActiveMonths = DISTINCTCOUNT('Calendar'[年月]) // 選択されている期間内の総月数(例: 四半期なら3)
VAR TotalShipping = SUM('PSI入力'[出荷]) // 期間内の総出荷数
VAR MonthlyAvgShipping = DIVIDE(TotalShipping, ActiveMonths) // 月あたりの平均出荷数
RETURN
IF(
    NOT(HASONEVALUE('Calendar'[日付])),
    DIVIDE( // 月あたりの回転数 = 月の平均出荷数 / 在庫平均
        MonthlyAvgShipping,
        [M在庫平均]
    )
)

カテゴリ:数値、書式:10進数、小数点以下の桁数:1、桁区切り(,)を使う

19) 在庫日数:[2026/05/16追加]

式 : 平均在庫 / 期間内の1日あたりの出荷量、期間の日数 / 期間回転率、平均在庫 / (月次出荷量 / 月平均日数)、平均在庫 * 月平均日数 / 月次出荷量

メジャーの名前:M在庫日数
数式:
=VAR TotalDays = COUNTROWS('Calendar') // 選択されている期間の総日数
RETURN
IF(
    NOT(HASONEVALUE('Calendar'[日付])),
    DIVIDE ( // 在庫日数 = 在庫平均 * 期間日数 / 期間出荷数合計
        [M在庫平均] * TotalDays,
        SUM('PSI入力'[出荷])
    )
)

カテゴリ:数値、書式:10進数、小数点以下の桁数:1、桁区切り(,)を使う

別の式
M在庫日数2:=DIVIDE( // 在庫日数 = (期間日数 / 期間月数) / 月の回転率
    DIVIDE(
        DISTINCTCOUNT('Calendar'[日付]),
        DISTINCTCOUNT('Calendar'[年月])
    ),
    [M月回転率]
)


3-5. ピボットテーブルで集計(Power Pivot)

20) ピボットテーブルを選択し、[ピボットテーブル分析]-[ピボットテーブル]-[オプション]の[レイアウトと書式]タブで"更新時に列幅を自動調整する"のチェックを外し、[表示]タブで"データの無いアイテムを行に表示する"と"データの無いアイテムを列に表示する"のチェックを必要に応じて入れる。

21) [デザイン]-[レポートのレイアウトv]で[表形式で表示]と[アイテムのラベルを全て繰り返す]を必要に応じて設定する。[小計v]や[総計v]を必要に応じて設定する。

22) ピボットテーブルを選択し、ピボットテーブルのフィールドで次のようにドラッグで展開する。

列:'Calendar'[年度]、'Calendar'[期]、'Calendar'[四半期]、'Calendar'[年月]。
行:顧客、製品。
Σ値。Σ値:入荷、出荷、M在庫、M月回転率。
250616psi08

23) 集計期間前を非表示にする:年度や期の手動フィルタで、集計期間前の期間のチェックを外します。

参考 : ピボットテーブルはコピーして、コピー先で別の項目展開やフィルタを掛けることができます。なので、日毎の推移を管理したい場合は、日付を列に展開したピボットテーブルを作成すればよいです。 

4. サンプルファイル

ダウンロード - 250616psi.zip

C:\Users\Public\Documents\250616psi に各ファイルを展開してください。[2026/05/16更新]

5. 参考リンク

  • Excel Power Pivot 入庫表と出庫表から在庫を算出 : 当ブログ : 2026/08/05
    https://bigarrow.tea-nifty.com/blog/2026/08/post-318f25.html
    本記事よりシンプルな内容です。

  • 入庫単価が変動する物の在庫金額と回転率 Excel Power Pivot : 当ブログ : 2026/05/15
    https://bigarrow.tea-nifty.com/blog/2026/05/post-c320e1.html
    在庫数だけでなく、出庫金額、在庫金額、金額ベースの回転率、在庫日数も集計しています。
    経営指標としては物価上昇も考慮する必要があるので、金額で管理することが多いように思います。

  • Power Queryで複数の表を結合する方法(まとめ)| 2025/11/05 | 当ブログ
    https://bigarrow.tea-nifty.com/blog/2025/11/post-341d5f.html
    複数シート、複数ファイルの在庫データをまとめる方法

  • Officeテンプレート「現金出納帳」「活動資金管理表 (サークル・コミュニティー運営)」の改造 | 2025/06/30 | 当ブログ
    https://bigarrow.tea-nifty.com/blog/2025/06/post-a208c0.html
    入庫を収入、出荷を支出、在庫を残高と考えると、出納帳に似ています。これは出納帳の記事です。

  • 完成数から納期を満たす納期と注残を計算 Excel Power Pivot : 当ブログ : 2026/05/12
    https://bigarrow.tea-nifty.com/blog/2026/05/post-cbe2e9.html

  • (Excel/Power BI)メジャーが予期しない値を返す原因とDAXコンテキストの理解 | 2025/03/18 | 当ブログ
    https://bigarrow.tea-nifty.com/blog/2025/03/post-8025c7.html
    メジャーを理解するためには、コンテキストとイテレータ関数とCALCULATE関数の理解が必要です。

  • GoogleスプレッドシートとPower BIを連携して在庫管理をする方法【ハンズオン解説】
    https://www.youtube.com/watch?v=2u69K0mK60s
    カレンダーテーブル使えよ、って突っ込みたくなりますが....(マトリックスでデータが無いところの累計が空欄になってます)

  • 【在庫管理表】便利な操作!エクセル効率アップ-28
    https://www.youtube.com/watch?v=2PNRBRbewyY
    現在の在庫が分かれば良いのであれば、このような方法もあります。

  • Excelで在庫管理を自動化|発注判断までできるテンプレ : 生産管理プロフェッショナルコミュニティ : 2026/03/13
    https://www.youtube.com/watch?v=aLAn4NqOw8w
    これは現在の在庫の把握には良いと思います。出力がリスト形式なので、Power Pivotは適切ではありません。この動画の方法かPower Queryが良いでしょう。時間軸の集計には向いていないです。
    このチャンネルは何でもExcelでやってしまう感じです。Excelしか使えない環境では役立ちます。Excel以外のソフトでやった方が良い事例も多くあります。例えば、プロジェクト管理・ガントチャートは、フリーのGanttProjectの方が良い場合もあります。Power BIやAccess等の方が良い場合もあるでしょう。

    これをExcel Power Pivotにしてみたのが次の記事です。
    ↓

  • Excelで在庫管理を自動化|発注判断までできるテンプレ を Power Pivot にするとどうなる? : 当ブログ : 2026/05/08
    https://bigarrow.tea-nifty.com/blog/2026/05/post-97cc09.html
    前記テンプレをPower Pivot化してみました。

  • 【Excel】在庫管理表の作成方法 | 20分で完成(初心者でも簡単自動アラート付き) : 30代からのパソコンスキルUP講座 : 2026/03/20
    https://www.youtube.com/watch?v=GBBgFUjsC0M
    入力兼集計表です。ワークシート式によるクロス表です。1シートで収まっているので分かりやすいです。ライン業務では無い物の在庫管理は、このような表でも良いと思います。
    月次や年次のまとめ報告、前年差、予実管理、回転率などに使おうとすると、データベース形式になっていないので、処理が面倒です。このようなデータは、Power Queryで取得しデータベース形式に変換するのが効率的です。Pover Pivotで集計すれば、集計しやすいでしょう。

  • 【自動化Excel】在庫管理表を作成して、安全在庫数を保つ方法 : 効率アップコンサルタント【みや】: 2020/12/11
    https://www.youtube.com/watch?v=4UUOXxP9bEc
    安全在庫管理です。ワークシート関数での事例ですが、Power Pivotを使用することができそうです。メジャーもそれほど難しくないと思われます。Power Pivotにすれば、最新だけでなく月次や年次などの推移も簡単に出せるようになると思います。

| | コメント (0)

Excel/Power Queryでデータブロックが横に並んでいるデータを縦にまとめる方法

Yahoo!知恵袋に、6列ごとに横に並んでいる複数行のデータから構成される子表(ブロック)を、1つにまとめる方法の質問がありました。
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10316235915
6列の最終列は隣のブロックとの区切りで空白列になっているので、データがあるのは5列になります。
各ブロックを示す識別子は、各ブロックの先頭行の2列目にあります。

これに対しワークシート式の回答がされています。配列を使用しているのですが、奇抜な処理ではないので理解はできると思います。でも、この式を発想するためには慣れが必要です。

|A10=TOCOL(    // 配列を列表示
|  IF((3:8<>"") * (MOD(COLUMN(3:8), 6) = 1),    // 空白ではない & 各ブロックの先頭列か?
|    INDEX(1:1,, COLUMN(3:8) + 1),    // TRUE⇒1行目の先頭列+1列目の値を配列に入れる
|    1/0),    // FALSE⇒エラーを配列に入れる
|  3,    // 空白とエラーを除外
|  TRUE)    // 列単位でスキャン
|
|B10=TOCOL(    // 配列を列表示
|  IF((3:8<>"") * (MOD(COLUMN(3:8), 6) = COLUMN(A1)),    // 空白ではない & 式がある列位置か?
|    3:8,    // TRUE⇒処理中の値を配列に入れる
|    1/0),    // FALSE⇒エラーを配列に入れる
|  3,    // 空白とエラーを除外
|  TRUE)    // 列単位でスキャン
※ Excelのワークシート式に//でコメントを書くことはできません。

これをPower Queryのクリック操作で行ってみました。結果としてはワークシート式より奇抜な処理になりました。しかし、複数シートや複数ブックなどへの応用はしやすいと思います。整形ノウハウもあるので、メモをしました。

Power Queryによる整形のポイント
1) 横方向の表のブロック毎に識別番号(整数除算)を付ける。
2) 行毎に情報が無いレイアウトの品番は、別クエリを作成し、識別番号(整数除算)をキーにマージする。
3) ピボット解除とピボットを使用して、各ブロックの表を合成する。


1. 整形前の表

元データ
品番 1111         品番 1112      
得意先 品名 数量 単価 納期   得意先 品名 数量 単価 納期
A商社 りんご 1 100 12月1日   A商社 もも 3 100 11月1日
B商社 バナナ 2 200 12月23日   B商社 バナナ 4 200 12月1日

1ブロック5列の表が1列の空白行を挟んで横に並んでいます。空白部分は、空白文字ではなくnullです。左上の品番がA1セルです。

2. 整形後の表

結合表
品番 得意先 品名 数量 単価 納期
1111 A商社 りんご 1 100 12月1日
1111 B商社 バナナ 2 200 12月23日
1112 A商社 もも 3 100 11月1日
1112 B商社 バナナ 4 200 12月1日

ワークシート式では左上の品番が元データと同じシートのA9セルです。Power Queryでは出力先のセルは、別シート、別ブックでもOKです。

3. Power Queryの作成手順

3-1. 元表クエリ

1) 取込:[データ]-[データの取得v]-[ファイルから>]-[Excelブックから]で整形前のブックを選択し、[インポート]で整形前のシートを選択し、[データの変換]。右のクエリの設定のプロパティの名前を"元表"に変更します。

※ 途中で自動生成される型の変更ステップは、元データの列が追加削除されるとエラーになるので、基本的には最後のステップを除き×で削除してください。

Column1 Column2 Column3 Column4 Column5 Column6 Column7 Column8 Column9 Column10 Column11
品番 1111         品番 1112      
得意先 品名 数量 単価 納期   得意先 品名 数量 単価 納期
A商社 りんご 1 100 12月1日   A商社 もも 3 100 11月1日
B商社 バナナ 2 200 12月23日   B商社 バナナ 4 200 12月1日

2) 横ブロック番号を付与するため転置する:[変換]-[入れ替え]。
(参考:Power Query等のデータベースを扱うソフトは、行と列で使用可能な機能が異なるので、機能が使えるように転置をします。)
3) 横ブロック番号を付与するためインデックスを付ける:[列の追加]-[インデックス列v]-[0から]。
4) インデックスから横グループ番号を生成:"インデックス"列を選択し[列の追加]-[標準v]-[除算(整数)]。(これが横グループ番号です)
5) 不要なインデックス列を削除:"インデックス列を選択し[ホーム]-[列の削除v]-[列の削除]。

Column1 Column2 Column3 Column4 整数除算
品番 得意先 A商社 B商社 0
1111 品名 りんご バナナ 0
  数量 1 2 0
  単価 100 200 0
  納期 45992 46014 0
        0
品番 得意先 A商社 B商社 1
1112 品名 もも バナナ 1
  数量 3 4 1
  単価 100 200 1
  納期 45962 45992 1

 

3-2. 品番クエリ

6) 品番テーブルを作成するクエリを作る:左ペインの"元表"クエリを右クリックし[参照]。右のクエリの設定のプロパティの名前を"品番"に変更します。
7) 品番の値のみ含む列を作る:[列の追加]-[条件列の追加]で次のように入力し[OK]。
- 新しい列名:品番
- 条件:列名:Column2、演算子:指定の値に等しい、値:品名、出力:Cloumn1、それ以外の場合:null。

Column1 Column2 Column3 Column4 整数除算 品番
品番 得意先 A商社 B商社 0  
1111 品名 りんご バナナ 0 1111
  数量 1 2 0  
  単価 100 200 0  
  納期 45992 46014 0  
        0  
品番 得意先 A商社 B商社 1  
1112 品名 もも バナナ 1 1112
  数量 3 4 1  
  単価 100 200 1  
  納期 45962 45992 1  

8) 不要な行を削除:"品番"列の右の▼をクリックし[空の削除]。
9) 不要な列を削除:"整数除算"と"品番"列を選択し[ホーム]-[列の削除v]-[他の列の削除]。
10) 品番の型を設定:"品番"列を選択し[変換]-[データ型v]-[テキスト]。

整数除算 品番
0 1111
1 1112

 

3-3. 連結クエリ

11) 連結テーブルを作成するクエリを作る:左ペインの"元表"クエリを右クリックし[参照]。右のクエリの設定のプロパティの名前を"連結"に変更します。
12) 不要な品番列を削除:"Column1"列を選択し[ホーム]-[列の削除v]-[列の削除]。
13) 不要な空の行を削除:"Column2"列の右の▼をクリックし[空の削除]。

Column2 Column3 Column4 整数除算
得意先 A商社 B商社 0
品名 りんご バナナ 0
数量 1 2 0
単価 100 200 0
納期 45992 46014 0
得意先 A商社 B商社 1
品名 もも バナナ 1
数量 3 4 1
単価 100 200 1
納期 45962 45992 1

※ この後のステップで横のブロック(Column3とColumn4)をピボット解除で1列にまとめます。 

14) 横ブロックの値を縦にまとめる:"Column2"と"整数除算"列を選択し[変換]-[列のピボット解除v]-[その他の列のピボット解除]。
(※ "Column3","Column4"は、レコード数によって増減数ので、この列名を使用するステップを作成してはいけない。)

Column2 整数除算 属性 値
得意先 0 Column3 A商社
得意先 0 Column4 B商社
品名 0 Column3 りんご
品名 0 Column4 バナナ
  途中 省略  
納期 1 Column4 45992
品番 1 Column3 1112
品番 1 Column4 1112

15) 項目を横に展開する:"Column2"列を選択し[変換]-[列のピボット]で値列に[値]、詳細オプションの値の集計関数を[集計しない]にして[OK]。

整数除算 属性 得意先 品名 数量 単価 納期
0 Column3 A商社 りんご 1 100 45992
0 Column4 B商社 バナナ 2 200 46014
1 Column3 A商社 もも 3 100 45962
1 Column4 B商社 バナナ 4 200 45992

解説:15)
ピボット列の説明が下記にあります。機械翻訳らしく、エラーの部分が分かりにくいです。
https://support.microsoft.com/ja-jp/office/-abc9c8da-3be9-44c4-886e-0be331ab387a
ブロック番号である"整数除算列"または"属性"が無いと、[集計しない]オプションエラーが出ます。理由は、片方だけだと値が複数して集計が必要になるからです。なので、2)~5)で横のブロック番号である"整数除算列"を生成しています。

Power Query -列のピボットの落とし穴と補正 / テクテク日記
https://marshal115.hatenablog.com/entry/2022/12/19/190051

16) 品番をマージする:[ホーム]-[クエリのマージv]-[クエリのマージ]で下のテーブルに[品番]を選び、上下の"整数除算"列をクリックして[OK]。(整数除算列=横グループ番号なので、これをキーにします。)
17) 品番を展開:"品番"列の矢印アイコンをクリックし、"品番"のみをチェックし、"プレフィックスとして使用"のチェックを外し[OK]。数式バーの"品番.1"を"品番"に書き換える。
- 変更前:= Table.ExpandTableColumn(マージされたクエリ数, "品番", {"品番"}, {"品番.1"})
- 変更後:= Table.ExpandTableColumn(マージされたクエリ数, "品番", {"品番"}, {"品番"})

整数除算 属性 得意先 品名 数量 単価 納期 品番
0 Column3 A商社 りんご 1 100 45992 1111
0 Column4 B商社 バナナ 2 200 46014 1111
1 Column3 A商社 もも 3 100 45962 1112
1 Column4 B商社 バナナ 4 200 45992 1112

18) 不要な列の削除:"整数除算"と"属性"列を選択し、[ホーム]-[列の削除v]-[列の削除]。
19) 列の順番を整える:"品番"列を選択し、[変換]-[移動v]-[先頭に移動]。
20) 型の設定:各列を選択し[変換]-[データ型]で適切な型を設定。any型(ABC123)は残さないこと。

21) 元データが変わったときは、[データ]-[すべて更新]で更新します。


4. サンプルファイル

ダウンロード - 250614pqclean.xlsx

C:\Users\Public\Documents\に保存してください。


5. 参考記事

Power Queryで表をリスト形式に整形する方法(まとめ)
https://bigarrow.tea-nifty.com/blog/2025/11/post-4925ca.html

項目が繰り返し横に伸びる、開始日と終了日のデータのみの表をモダンExcelで集計
https://bigarrow.tea-nifty.com/blog/2025/07/post-258734.html


6. 余談

1) 可読性
本例は、頭で考える処理と似た手順でできるVBAやワークシート式の方が創造しやすいと思われます。
Power Queryでは立体パズルを解くような仕組みになるので、想像しにくいです。一方、Power Queryでは各ステップの動きを実データで確認しやすいので、可読性は良いと思います。
どの方法が良いかは個人の好みになりますが、プログラミングかできない人にとっては、Power Queryの方が可読性は良い気もします。(Power Query Mのコードを直接書いたものを除きます。)

| | コメント (0)

Excel Power Query Mでカレンダを作成し、メジャーで前の値との差を計算

前書き

ExcelのPower QueryとPower Pivotでピボットテーブルを作るときに使用する、集計する元データの日付範囲だけを含むカレンダーテーブル(日付テーブル)を、Power Query Mで生成するクエリを作成しました。

これを使うと、集計データの日付範囲が変わった場合、データの更新により集計データの日付範囲をカバーするカレンダに更新されるので、手動でカレンダテーブルの範囲を修正する必要がありません。

カレンダテーブルにより任意の時間軸のデータを抽出できるので、累計、移動平均、前期比較など時間軸の計算処理ができます。この例として各集計項目に前の値(前月、前四半期、前半期、前年)との差を求めるメジャー(DAX式)を作成しました。

カレンダテーブルを使うことで、ピボットテーブルのグループ化で使われる暦とは異なる区切りで集計することができます。本例では4月の年度始まりとしています。その他、月締めを25日にする、決算月を9月にするなども、カレンダテーブルの修正で対応することができます。

各コードは、ChatGPTを利用して作成しました。(もっと簡潔な記述ができそうな気がします。)

参考


1. 集計元データ(例)

集計元データ名:'Data'
[日付], [年月], [売上]
2025/4/1, 25/04, 1000
2026/3/31, 26/03, 1000

※ カレンダーテーブルを作成するクエリでは、集計元データの[日付]列を参照します。この例では、2025/4/1~2026/3/31までのカレンダを後述のクエリで生成します。


2. 1日毎のカレンダテーブル(CalendarD)

1日毎のテーブルを作成するコードです。Power Pivotの仕様に従った日付テーブルです。DAXのタイムインテリジェンス関数を使うことができます。

項目:日付、年度.、月、年月、四半期、期、年度
250605calendard

式の中のData[日付]は、カレンダーテーブルでリレーションする集計元データ(ファクトテーブル)の[日付]です。2つあるのは、元データに日付列が2つある場合(開始日と終了日など)の対応用です。(MaxDateが2つあるのは、ファクトテーブルや日付列が2つある場合の例です。)

// ファクトテーブルの日付範囲の日毎のカレンダテーブルを生成する
let

  // ファクトテーブル'Data'の最小日付を取得
  MinDate = List.Min(Data[日付]),

  // ファクトテーブル'Data' の最大日付と最大日付を取得し、大きい方を選択
  Max1Date = List.Max(Data[日付]),
  Max2Date = List.Max(Data[日付]),
  EndDate = if Max1Date > Max2Date then Max1Date else Max2Date,

  // 連続した日付のリストを作成
  DateList = List.Dates(MinDate, Duration.Days(EndDate - MinDate) + 1, #duration(1,0,0,0)),

  // カレンダーテーブル作成
  CalendarTable = Table.FromList(DateList, Splitter.SplitByNothing(), {"日付"}),

  // 年度(4月始まり)=yyyy、月=m、年月=yy/mm
  AddColumns = Table.AddColumn(CalendarTable, "年度.", each Date.Year(Date.AddMonths([日付], -3)), Int64.Type),
  AddColumns2 = Table.AddColumn(AddColumns, "月", each Date.Month([日付]), Int64.Type),
  AddColumns3 = Table.AddColumn(AddColumns2, "年月", each
    Text.PadStart(Text.From(Date.Year([日付]) - 2000), 2, "0") & "/" &
    Text.PadStart(Text.From(Date.Month([日付])), 2, "0"), type text),

  // 四半期:4~6月=yy/1Q, 7~9月=yy/2Q, 10~12月=yy/3Q, 1~3月=yy/4Q
  AddColumns4 = Table.AddColumn(AddColumns3, "四半期", each
    let
      FiscalYear = Date.Year(Date.AddMonths([日付], -3)) - 2000,
      Quarter = Number.RoundDown((Number.Mod(Date.Month([日付]) + 8, 12)) / 3) + 1
    in
      Text.PadStart(Text.From(FiscalYear), 2, "0") & "/" & Text.From(Quarter) & "Q", type text),

  // 期:4~9月=yy/1H, 10~3月=yy/2H
  AddColumns5 = Table.AddColumn(AddColumns4, "期", each
    let
      FiscalYear = Date.Year(Date.AddMonths([日付], -3)) - 2000,
      Half = if Date.Month([日付]) >= 4 and Date.Month([日付]) <= 9 then "1H" else "2H"
    in
      Text.PadStart(Text.From(FiscalYear), 2, "0") & "/" & Half, type text),

  // 年度:yy年度
  AddColumns6 = Table.AddColumn(AddColumns5, "年度", each
    let
      FiscalYear = Date.Year(Date.AddMonths([日付], -3)) - 2000
    in
      Text.PadStart(Text.From(FiscalYear), 2, "0") & "年度", type text),
  変更された型 = Table.TransformColumnTypes(AddColumns6,{{"日付", type date}})

in
  変更された型


使い方:
1) 集計するデータをPower Queryに取込みます。
2) Excel-[データ]-[データの取得v]-[その他のデータソースから]-[空のクエリ]、またはPower Queryエディタ-[ホーム]-[新しいソースv]-[その他のソース]-[空のクエリ]で、[ホーム]-[詳細エディタ]を開き、サンプルファイルのコードを上書き貼付けします。
3) コード中の'Data'[日付]を、集計するデータの名前に変更します。

参考:項目を追加したPower Query Mによる日付テーブルの例

3. 月毎のカレンダーテーブル(CalendarM)

月毎のカレンダを作成するコードです。Power Pivotの日付テーブルの仕様ではありません。なので、タイムインテリジェンス関数は使えません。その代わり、月、四半期、半期毎のインテックス(連番)を付けています。インデックスをFILTER関数で使用することにより、タイムインテリジェンス関数を使用せずに同様の期間集計をすることができます。

項目:日付、年度.、月、年月、四半期、期、年度、mid、qid、hid

インデックスの説明
- midは月毎の連番です。
- qidは四半期毎の連番です。
- hidは半期毎の連番です。
- 年度は、年度.が数値なので、これをインテックスとして使用します。
250605calendarm

Data[日付]は、カレンダーテーブルでリレーションする集計元データ(ファクトテーブル)の[日付]です。2つあるのは、元データに日付列が2列ある場合(開始日と終了日など)などの対応用です。

// ファクトテーブルの日付範囲の月毎のカレンダテーブルを生成する
let
  // ファクトテーブル'Data'の最小日付と最大日付(月初)を取得
  MinDate = Date.StartOfMonth(List.Min(Data[日付])),
  Max1Date = List.Max(Data[日付]),
  Max2Date = List.Max(Data[日付]),
  MaxDate = if Max1Date > Max2Date then Max1Date else Max2Date,
  EndDate = Date.StartOfMonth(MaxDate),

  // 月次リスト生成
  MonthList = List.Generate(
    () => MinDate,
    each _ <= EndDate,
    each Date.AddMonths(_, 1),
    each _
  ),
  CalendarTable = Table.FromList(MonthList, Splitter.SplitByNothing(), {"日付"}),

  // 各種列を追加(年度:yyyy、月:m、年月:yy/mm、四半期:yy/qQ、期:yy/hH、年度:yy年度)年度始まりは4月
  Add1 = Table.AddColumn(CalendarTable, "年度.", each Date.Year(Date.AddMonths([日付], -3)), Int64.Type),
  Add2 = Table.AddColumn(Add1, "月", each Date.Month([日付]), Int64.Type),
  Add3 = Table.AddColumn(Add2, "年月", each
    Text.PadStart(Text.From(Date.Year([日付]) - 2000), 2, "0") & "/" &
    Text.PadStart(Text.From(Date.Month([日付])), 2, "0"), type text),

  Add4 = Table.AddColumn(Add3, "四半期", each
    let
      FiscalYear = Date.Year(Date.AddMonths([日付], -3)) - 2000,
      Quarter = Number.RoundDown((Number.Mod(Date.Month([日付]) + 8, 12)) / 3) + 1
    in
      Text.PadStart(Text.From(FiscalYear), 2, "0") & "/" & Text.From(Quarter) & "Q", type text),

  Add5 = Table.AddColumn(Add4, "期", each
    let
      FiscalYear = Date.Year(Date.AddMonths([日付], -3)) - 2000,
      Half = if Date.Month([日付]) >= 4 and Date.Month([日付]) <= 9 then "1H" else "2H"
    in
      Text.PadStart(Text.From(FiscalYear), 2, "0") & "/" & Half, type text),

  Add6 = Table.AddColumn(Add5, "年度", each
    let
      FiscalYear = Date.Year(Date.AddMonths([日付], -3)) - 2000
    in
      Text.PadStart(Text.From(FiscalYear), 2, "0") & "年度", type text),

  // mid の追加(月の連番)
  AddMid = Table.AddIndexColumn(Add6, "mid", 1, 1, Int64.Type),

  // 四半期ごとのユニーク値に連番を付ける(四半期の連番)
  UniqueQuarters = Table.Distinct(Table.SelectColumns(AddMid, {"四半期"})),
  SortedQuarters = Table.Sort(UniqueQuarters, {"四半期", Order.Ascending}),
  IndexedQuarters = Table.AddIndexColumn(SortedQuarters, "qid", 1, 1, Int64.Type),

  // 期ごとのユニーク値に連番を付ける(期の連番)
  UniqueHalves = Table.Distinct(Table.SelectColumns(AddMid, {"期"})),
  SortedHalves = Table.Sort(UniqueHalves, {"期", Order.Ascending}),
  IndexedHalves = Table.AddIndexColumn(SortedHalves, "hid", 1, 1, Int64.Type),

  // 必要な列だけを残してマージ
  QidOnly = Table.SelectColumns(IndexedQuarters, {"四半期", "qid"}),
  HidOnly = Table.SelectColumns(IndexedHalves, {"期", "hid"}),

  // 元のテーブルに結合
  JoinQid = Table.NestedJoin(AddMid, "四半期", QidOnly, "四半期", "QidTable", JoinKind.LeftOuter),
  ExpandQid = Table.ExpandTableColumn(JoinQid, "QidTable", {"qid"}),

  JoinHid = Table.NestedJoin(ExpandQid, "期", HidOnly, "期", "HidTable", JoinKind.LeftOuter),
  ExpandHid = Table.ExpandTableColumn(JoinHid, "HidTable", {"hid"}),

  FinalTable = Table.TransformColumnTypes(ExpandHid, {{"日付", type date}})
in
  FinalTable

 

以下、カレンダーテーブルの応用例を紹介します。

4. 1日毎のカレンダーテーブル(CalendarM)とタイムインテリジェンス関数を使用した前の値との差を求めるメジャー

小計を表示するためには、カレンダーテーブルとメジャーを使用します。
250605calendarpd

M増減D:=
// コンテキストフィルタのレベル
VAR IsMonthLevel = HASONEVALUE('CalendarD'[年月])
VAR IsQuarterLevel = HASONEVALUE('CalendarD'[四半期])
VAR IsHalfYearLevel = HASONEVALUE('CalendarD'[期])
VAR IsYearLevel = HASONEVALUE('CalendarD'[年度])
// 共通の現在値
VAR CurrentSales = SUM('Data'[売上])
// 前月の売上
VAR PrevMonthSales =
  CALCULATE(
    SUM('Data'[売上]),
    PREVIOUSMONTH('CalendarD'[日付])
  )
// 前四半期の売上
VAR PrevQuarterSales =
  CALCULATE(
    SUM('Data'[売上]),
    PREVIOUSQUARTER('CalendarD'[日付])
  )
// 前半期の売上(≒2四半期前)
VAR PrevHalfYearSales =
  CALCULATE(
    SUM('Data'[売上]),
    DATESINPERIOD('CalendarD'[日付], MIN('CalendarD'[日付]) - 1, -6, MONTH)
  )
// 前年度の売上
VAR PrevYearSales =
  CALCULATE(
    SUM('Data'[売上]),
    SAMEPERIODLASTYEAR('CalendarD'[日付])
  )
// 前期間のデータの存在チェック
VAR HasPrevMonth =
  NOT ISBLANK(PrevMonthSales)
VAR HasPrevQuarter =
  NOT ISBLANK(PrevQuarterSales)
VAR HasPrevHalfYear =
  NOT ISBLANK(PrevHalfYearSales)
VAR HasPrevYear =
  NOT ISBLANK(PrevYearSales)
// 実行
RETURN
  SWITCH(
    TRUE(),
    IsMonthLevel, IF(HasPrevMonth, CurrentSales - PrevMonthSales, BLANK()),
    IsQuarterLevel, IF(HasPrevQuarter, CurrentSales - PrevQuarterSales, BLANK()),
    IsHalfYearLevel, IF(HasPrevHalfYear, CurrentSales - PrevHalfYearSales, BLANK()),
    IsYearLevel, IF(HasPrevYear, CurrentSales - PrevYearSales, BLANK()),
    BLANK()
  )


使用方法:
1) ピボットテーブルを選択し、ピボットテーブルのフィールドの集計データを右クリックし、[メジャーの追加]。
2) 数式にサンプルファイルの=からのコードを貼り付ける。
3) コード中の'Data'[売上]を集計データの名前に変更する。

このメジャーは、前期間との差を計算するメジャーです。6月であれば6月-5月、25/1Qであれば25/1Q-24/4Qを計算します。
前期間のデータが無い時は値を返しません。もし、前期間と今期間のどちらかのデータがあれば値を返すようにするなら、次の記事のメジャーを使用してください。

ヒント:
このメジャーは期間によって、前期間の対象が異なるのでSWITCHで場合分けをしています。もし、前年同期間差を出すのであれば、SAMEPERIODLASTYEAR('CalendarD'[日付])だけで良いので、CALCULTATEの式が1つだけになり簡単です。


5. 月毎のカレンダーテーブル(CalendarM)とインデックスを使用した前の値との差を求めるメジャー

月毎のカレンダーではタイムインテリジェンス関数が使えませんが、インデックスとFILTERを用いることで、同様の計算ができます。
250605calendarpm

M増減M:=
VAR IsMonthLevel = HASONEVALUE('CalendarM'[年月])  // コンテキストフィルタのレベル
VAR IsQuarterLevel = HASONEVALUE('CalendarM'[四半期])
VAR IsHalfYearLevel = HASONEVALUE('CalendarM'[期])
VAR IsYearLevel = HASONEVALUE('CalendarM'[年度])
// 共通の現在値
VAR CurrentSales = SUM('Data'[売上])
// 前月の売上
VAR PrevMonthSales =
  CALCULATE(
    SUM('Data'[売上]),
    FILTER(ALL('CalendarM'), 'CalendarM'[mid] = MAX('CalendarM'[mid]) - 1)
  )
// 前四半期の売上
VAR PrevQuarterSales =
  CALCULATE(
    SUM('Data'[売上]),
    FILTER(ALL(CalendarM), 'CalendarM'[qid] = MAX('CalendarM'[qid]) - 1)
  )
// 前半期の売上
VAR PrevHalfYearSales =
  CALCULATE(
    SUM('Data'[売上]),
    FILTER(ALL(CalendarM), 'CalendarM'[hid] = MAX('CalendarM'[hid]) - 1)
  )
// 前年度の売上
VAR PrevYearSales =
  CALCULATE(
    SUM('Data'[売上]),
    FILTER(ALL(CalendarM), 'CalendarM'[年度.] = MAX('CalendarM'[年度.]) - 1)
  )
// 前期間存在チェック
VAR HasPrevMonth =
  NOT ISBLANK(PrevMonthSales)
VAR HasPrevQuarter =
  NOT ISBLANK(PrevQuarterSales)
VAR HasPrevHalfYear =
  NOT ISBLANK(PrevHalfYearSales)
VAR HasPrevYear =
  NOT ISBLANK(PrevYearSales)
// 実行
RETURN
  SWITCH(
    TRUE(),
    IsMonthLevel, IF(HasPrevMonth, CurrentSales - PrevMonthSales, BLANK()),
    IsQuarterLevel, IF(HasPrevQuarter, CurrentSales - PrevQuarterSales, BLANK()),
    IsHalfYearLevel, IF(HasPrevHalfYear, CurrentSales - PrevHalfYearSales, BLANK()),
    IsYearLevel, IF(HasPrevYear, CurrentSales - PrevYearSales, BLANK()),
    BLANK()
  )


6. サンプル

ダウンロード - 250604calendar.xlsx

 

7. ピボットテーブルの集計フィールドで前の値からの差を表示する(参考)

参考にカレンダテーブルとメジャーを使用せず、集計フィールドで作成する方法を紹介します。

[ピボットテーブル分析]-[フィールド/アイテム/セット-]-[集計フィールド]で、"計算の種類"を[基準値との差分]、"基準フィールド"で比較する項目を選び、"基準アイテム"に[(前の値)]を選択します。
ピボットテーブルで小計を表示しない場合は、これで問題ありません。

しかし、小計を表示すると、次の問題が発生します。
- 小計の前の値からの差が表示されない。
- 小計の直後の前の値からの差が表示されない。

参考:
【Excel】数式なし。ピボットテーブルだけで前月比較表を作る
https://www.youtube.com/watch?v=9zKmhxuKHNo

8. 関連記事


9. 参考(外部リンク)

| | コメント (0)

« 2025年5月 | トップページ | 2025年7月 »