テクテク日記

テクテク=テクノロジー&一歩ずつ(テクテク)

在庫メジャーの留意点

Power BIで在庫分析を行う場合、DAXで在庫メジャーを記述する必要があります。在庫が必要な理由は、

商品・製品の売れるタイミングと仕入れたり、製造したりするタイミングにズレがある

ためであり、機会損失(欠品)を防ぐために必要なものとなります。在庫は通常、時系列(日付ベース)では集計できず、貸借対照表の中にある資産項目(例: 現金残高)と同じように、スナップショット(その時点)の指標となります。従って、昨日の在庫と本日の在庫は売上高のように、単純にSUMすることはできず、CALCULATEを使って日付テーブルでフィルターしてからSUMで集計してあげる必要があります。

なお、デモファイルは一番下よりダウンロードできます。

日付テーブル別在庫メジャー

DAXメジャーで算出された在庫高は、スライサー(フィルター)の状態(粒度)によって、在庫高が空白となることがあります。例えば、Contoso RetailデータベースからDateとInventoryというシンプルなデータモデルを考えてみます。

  • InvQty(LASTDATEを使った在庫数量メジャー)
InvQty = 
    CALCULATE ( 
        SUM ( Inventory[OnHandQuantity] )
        LASTDATE ( 'Date'[Datekey] )
    )

このメジャーを年月日ベース(DateKey)で見ると、1週間おきに正しく値が表示されているのが分かります。

しかしならが、これを年月別にプロットしてみると、以下のように数値がきちんと算出される月とされない月に分かれてしまいます。

理由として、LASTDATEが年月ベースでフィルターされた場合、常にその月の最後の日をテーブルフィルターとして抽出しているためです(※テーブルフィルターは値が1つだけの場合はスカラー値となるため、InvQty_Monthは下記テーブルにてエラーを起こさずに計算できています)。

  • InvQty_Month(LASTDATEだけで見た場合の日付)
InvQty_Month = LASTDATE ( 'Date'[Datekey] )

上記全ての月について、最終日に関わらず年月ベースで在庫高を算出したい場合、下記のDAXメジャーを用いてテーブルフィルターを作り、最後に残高があった日付を抽出する必要があります。

  • InvQty_Month_WithData(LASTDATEだけで見た場合の日付)
InvQty_Month_WithData =
LASTNONBLANK ( 'Date'[Datekey], CALCULATE ( COUNTROWS ( Inventory ) ) )

  • InvQty2(LASTNONBLANKで作った在庫数量メジャー)
InvQty2 =
CALCULATE (
    SUM ( Inventory[OnHandQuantity] ),
    LASTNONBLANK ( 'Date'[Datekey], CALCULATE ( COUNTROWS ( Inventory ) ) )
)

注意すべき点は、LASTNONBLANKの第2の引数ではContext Transitionが必要であり、CALCULATEを使うことで意図的にこれを作り出していることです(ここはメジャーをそのまま入れてもOK)。

在庫高はデータ量が多いため、毎日の実績をシステムから抽出することが難しい場合もあります。そのため、Weeklyベースで在庫データを理論値として把握することも珍しくありません。従って、月次ベースで在庫高を確認するため、各月の最終日ではなく、システムからデータを抽出できる日付で在庫高を算出する必要がある場合には今回のような計算手法が1つの手段であることが考えられます。

在庫メジャーの間違った計算

ここから日次ベースで在庫データがあり、それを定点観測を行う必要がある場合について見ていきます。先ほどのメジャーと同じように、シンプルな例を考えてみます。ここでの要件として、日別の在庫高を正しく把握することとします。

上図のように、シンプルなスタースキーマのモデルがあり、在庫数量や日付チェック用のメジャーを計算しています。

  • 在庫数LastNonBlank(LASTNONBLANKで作った在庫数メジャー)
在庫数LastNonBlank =
CALCULATE (
    SUM ( Inventory[InventoryQuantity] ),
    LASTNONBLANK (
        'Date'[Date],
        CALCULATE ( SUM ( Inventory[InventoryQuantity] ) )
    )
)
  • 在庫数_正(日別で見た場合の正しいメジャー)
在庫数_正 =
VAR _curret_date =
    CALCULATE ( MAX ( Inventory[Date] ), ALLEXCEPT ( Inventory, 'Date' ) )
VAR _result =
    CALCULATE ( 
        SUM ( Inventory[InventoryQuantity] )
        'Date'[Date] = _curret_date
        )
RETURN
    _result
  • 日付Check(在庫数がある最終日付)
日付Check =
LASTNONBLANK (
    'Date'[Date],
    CALCULATE ( SUM ( Inventory[InventoryQuantity] ) )
)

Dateベースで見ると、どちらのメジャーでも正しい結果が返っています。理由は、日付ベースでフィルターを行っていることであり、「日付Check」メジャーで算出された値がテーブルフィルターとして機能しているためです。

一方、下図のように、CategoryとProductで見ると、この2つのメジャーに差が出てくるようになりました。「在庫数LastNonBlank」メジャーではSurface Pro 4で数値が算出されているのに対して、「在庫数_正」のほうは空白となっています。

もうお気づきだと思いますが、日付Checkを見ると、Surface Pro 4に関して、最後に在庫があった日付が2023-03-19となっているからです。以前の記事で紹介しましたが、

今フィルターされている状態を常に把握

することは重要で、何をフィルターしているのかを把握することがミスを防いでくれます。今回の例では日別に在庫数量を確認していることになりますので、直近が2023-03-20であるとすると、Surface Pro 4に残数があるのは間違い、ということになります。

最後に

在庫メジャーに限らないですが、Semi-additive(半加法的)メジャーを計算する際に注意が必要です。Power BIでは売上等のメジャーがメインとして取り上げられることが多いですが、実は在庫のようなメジャーのほうが奥が深く、いろいろ研究していくと面白いと思います。

>>サンプルダウンロード