小計で四半期末の数字だけを集計する

「集計は四半期ごとだけど、期中の推移も見たい」的なお話です。
この手の要望に対応した事があるので、忘れないうちに書いておきます。

ExcelのPower Pivotでも使えます。
#やりたいこと
実績のデータがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/30a3b542-af59-620f-bfff-8189c1aa7194.png)

四半期の小計が3ヶ月の合計になってますが、これを期末(3月、6月、9月、12月)の数値にしたい。
つまりこういう事。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/37141704-255d-32f2-93d2-e042679184fc.png)

完成イメージはこちら。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/f86b3f48-6be5-a013-ab08-3c7ec3d482e6.png)

ついでに四半期ごとに設定された計画地との比較もやる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/30eea770-832d-4802-322a-f06747a2154a.png)

#使うデータと設定
##リレーション
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/f9f92255-1fb6-f818-267e-1c90db5621bd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/16c5e827-2ca0-ca50-b321-9cbc77c2c130.png)

##データセット
在庫実績
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/47e149f7-2d4c-d063-4ba1-c88c7d1f2438.png)
在庫計画
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/30ec426e-477c-07c9-ede5-af4b1d6a34e8.png)

**在庫実績テーブルは日付がyyyyMM形式の「年月」列で構成されています。**
また、**在庫計画は四半期ごとの粒度です。**
このままでは日付テーブルとリレーションを組めないので、**年月ブリッジと四半期ブリッジを中間テーブルとしてブリッジさせます。**

年月ブリッジ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/c073f5a0-d5ff-63d2-5264-cb988ffa4f46.png)
四半期ブリッジ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/411a2a39-8fe2-4cd4-afe9-e4bab859358a.png)

##日付テーブル

```C#:日付テーブル
日付テーブル = 
ADDCOLUMNS(
    CALENDAR(DATE(2018,4,1),DATE(2021,3,31)),
    "年_数値", YEAR ( [Date] ),
    "年_yyyy年",FORMAT([Date],"yyyy年"),
    "月_数値", MONTH ([Date]),
    "月_MM月", FORMAT ([Date], "MM月" ),
    "日_数値", DAY ([Date]),
    "日_DD日", FORMAT([Date],"DD日"),
    "年月_数値", VALUE(FORMAT([Date], "yyyyMM" )),
    "年月_yy年MM月", FORMAT ( [Date], "yy年MM月" ),
    "年度_数値",if(MONTH([Date])>3,YEAR([Date]),YEAR([Date])-1),
    "年度_0年度",FORMAT(if(MONTH([Date])>3,YEAR([Date]),YEAR([Date])-1),"0年度"),
    "四半期_数値", if(MONTH([Date])<4,4,if(MONTH([Date])<7,1,if(MONTH([Date])<10,2,3))),
    "四半期_0Q", if(MONTH([Date])<4,"4Q",if(MONTH([Date])<7,"1Q",if(MONTH([Date])<10,"2Q","3Q"))),
    "年度四半期", if(MONTH([Date])<4,YEAR([Date])&"4Q",if(MONTH([Date])<7,YEAR([Date])&"1Q",if(MONTH([Date])<10,YEAR([Date])&"2Q",YEAR([Date])&"3Q"))),
    "年度四半期末", SWITCH(MONTH([Date]),3,TRUE(),6,TRUE(),9,TRUE(),12,TRUE(),FALSE())
    )
```
##メジャー
事前に定義したメジャーはこちら。

```C#:メジャー
在庫実績合計 = SUM('在庫実績'[在庫実績])
在庫計画合計 = SUM('在庫計画'[在庫計画])
```

#小計で四半期末の数字だけを集計する
##どういうデータにすれば出来そうか
期末の実績だけ抜き出せれば何とかなりそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/d67a17c8-a64c-f5c7-0633-111fbd89017b.png)

##メジャーの準備
###期末の数字を取り出す
実は難しいことをしなくてもできます。
**日付テーブルを作った際に、期末の月が`True`、それ以外が`False`になる計算列`年度四半期末`を作ってあります。**

```C#:年度四半期末
"年度四半期末", SWITCH(MONTH([Date]),3,TRUE(),6,TRUE(),9,TRUE(),12,TRUE(),FALSE())
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/415d2132-a624-ab5f-3d21-7a867525faeb.png)

後はCALCULATEにフィルター式として組み込むだけです。

```C#:期末実績
期末実績 = CALCULATE([在庫実績合計],'日付テーブル'[年度四半期末]=TRUE())
```

これで期末の実績が取り出せました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/d8d5c6f4-7494-eb39-5c93-c5fa5c263ee6.png)

###四半期小計と総計以外を識別する
[ISINSCOPE 関数](https://dax.guide/isinscope/)を使います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/507fe094-aa17-916d-79fb-67947bc91f4d.png)

`ColumnName`に指定する列は`'日付テーブル'[月_MM月]`です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/e8eedabb-43a8-7cce-7558-4f3ba3ab28ae.png)


**この式を使う事で月ごとの集計なら`True`、それ以外は`False`を返します。**

```C#:月集計チェック
月集計チェック = ISINSCOPE('日付テーブル'[月_MM月])
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/3cf3baa9-0b50-bbd4-0537-f596db551e54.png)

期中の計算でもしっかり働いてくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/31c8ed25-995d-f7b6-e572-b6de72fde77c.png)

ここら辺の手順は**Power BI の神が[メジャーの特性 や 見出しの階層に合わせて集計する には](https://qiita.com/PowerBIxyz/items/17d5d531ea074a43867b)**で詳しく解説してくれています。

###四半期小計と総計を期末の数字にする
既に`ISINSCOPE('日付テーブル'[月_MM月])`で`True`になるのが月ごとの集計と分かっています。
なので**`True`なら`在庫実績合計`を、`False`なら`[期末実績]`を表示するようにします。**

**ここでは[SWITCH 関数](https://dax.guide/switch/)を使います。**

```C#:小計と総計が期末の数字
在庫実績合計 = SUM('在庫実績'[在庫実績])
期末実績 = CALCULATE([在庫実績合計],'日付テーブル'[年度四半期末]=TRUE())

小計と総計が期末の数字 = SWITCH(TRUE(),ISINSCOPE('日付テーブル'[月_MM月]),[在庫実績合計],[期末実績])
```

これで目的の表が出来ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/bc21a840-276b-2659-6136-b95bb7288caf.png)

#四半期ごとに設定された計画値と比較する
次は四半期ごとに設定された計画値との比較を作ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/3f356cb3-344c-8a1a-7c0b-422f92a7e000.png)

実はこのままでも四半期ごとの比較はできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/0e7db303-dc71-69e4-e7f8-214292951652.png)

けど、折角やるなら全期間を比較したいですよね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/3a5935a8-bc70-f43f-008a-4bfdccf3d244.png)

##空白の月を埋める
全期間で比較するためには空白の月を計画値で埋める必要があります。
まず**`CALCULATE`でフィルターコンテキストを上書きします。**

```c#:CALCULATEでフィルターコンテキストを上書き
CALCULATEでフィルターコンテキストを上書き = CALCULATE([在庫計画合計],ALL('日付テーブル'))
```
フィルター式に`ALL('日付テーブル')`を使う事で、空白の部分を全て埋められました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/c08f87d4-5abe-7716-3ec6-e60b01fa3fad.png)

しかし**全て総計値で埋まってしまってるので、これを各四半期の計画値に変える必要があります。**
そこでフィルター式に`VALUES('日付テーブル'[年度四半期])`を加えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/a7142fef-2874-8111-6105-eb3d98cf5946.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/687a6059-01e0-d2fa-f843-aded566d7478.png)

こうすることで**`ALL('日付テーブル')`で日付テーブルのフィルターを全て外した上で、`年度四半期`ごとのフィルターだけが適用された状態にフィルターコンテキストを上書きできます。**

式はこうなります。

```c#:実績比較用在庫計画
実績比較用在庫計画 = CALCULATE([在庫計画合計],ALL('日付テーブル'),VALUES('日付テーブル'[年度四半期]))
```

これで正しく各四半期の計画値で空白を埋める事が出来ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/b8f640f3-65f5-6aca-7142-2d99cf3a3bc6.png)

##計画と実績を比較する
後は計画と実績を引き算するだけです。

```c#:
作成した計画 = CALCULATE([在庫計画合計],ALL('日付テーブル'),VALUES('日付テーブル'[年度四半期]))
作成した実績 = SWITCH(TRUE(),ISINSCOPE('日付テーブル'[月_MM月]),[在庫実績合計],[期末実績])

計画-実績 = [作成した計画]-[作成した実績]
```

全期間の比較が完成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/2d50d8d6-d8d5-1ade-2584-8f46c8b3d0f7.png)

#まとめ

- **メジャーだけではなく、計算列も使う**
    - 計算列でテーブルに固定値を持った方が便利な場合も沢山あります
- **テーブルやマトリックスの行、列から生まれるフィルターコンテキストを条件式に利用する**
    - DAX式はフィルターの有無であったり、フィルターの結果1つの値が残るかを取得できる関数があります
- **個別の値と小計、総計を別々の式で表示する事が出来る**
    - DAX式は自分で小計、総計だけ別の計算式にする事が出来るので、学べば学ぶほど表現が広がります。

DAX式はExcelと大分作法が違いますが、Excel関数だけでは難しい集計が出来ますよー。