GROUPBY関数の研究🤔～GROUPBY関数の使いどころ編～

# はじめに

すこし複雑なメジャーを記述しようとすると、避けては通れないテーブル操作関数。主要な`SUMMARIZE`、`ADDCOLUMNS`、 `SUMMARIZECOLUMNS`などを研究してみます。

**テーブル操作関数シリーズ**

続きものです。

1. [SUMMARIZE関数の研究～集計列の追加はなぜ非推奨なのか🤔～](https://qiita.com/akihiro_suto/items/a317d560fd298403bc15)
1. [ADDCOLUMNS関数の研究～集計列追加のベストプラクティス🤔～](https://qiita.com/akihiro_suto/items/ced4c9053f11fbe2baf3)
1. [集計列追加のベストプラクティス🤔～とはいえ例外だってあるぞ～](https://qiita.com/akihiro_suto/items/331aee0734b98c0ec345)
1. [SUMMARIZECOLUMNS関数の研究～SUMMARIZE関数は非推奨?🤔～](https://qiita.com/akihiro_suto/items/1a7c08aaf369ee1cc3a3)
1. [GROUPBY関数の研究🤔～基本動作確認編～](https://qiita.com/akihiro_suto/items/aaf2e4c98cf88833dc63)

## DAXクエリ＆DAX.do

https://dax.do/

今回の検証はDAX.do上でDAXクエリを書いて検証していきます。
DAXクエリがわからない方は先にこの記事を読んで、DAX.doで少し触ってからのほうが理解が進むでしょう。

DAXクエリについてはこちらの記事を参照してください。

https://qiita.com/hanaseleb/items/96b80210a7fc20c36a13

# 参考記事

https://www.sqlbi.com/articles/nested-grouping-using-groupby-vs-summarize/

# 復習

列のグループ化をするだけなら、`GROUPBY`関数でも、`SUMMARIZE`関数でも結果は一緒。書き方も一緒。

```
EVALUATE
GROUPBY (
    Sales,
    'Product'[Brand],
    'Product'[Category]
)
```

```
EVALUATE
SUMMARIZE (
    Sales,
    'Product'[Brand],
    'Product'[Category]
)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/0efe2361-6549-75e7-d149-11b4c4c7028b.png)

## 集計列の追加をするときは`CURRENTGROUP ()`関数

集系列を追加するときは、`GROUPBY`関数の場合は`CURRENTGROUP ()`関数を使用できる。グループ化した表を再利用できる。

```
EVALUATE
GROUPBY (
    Sales,
    'Product'[Brand],
    'Product'[Category],
    "SalesAmt",
        SUMX (
            CURRENTGROUP (),
            Sales[Net Price] * Sales[Quantity]
        )
)
ORDER BY [SalesAmt] DESC
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/1b77220d-d9d3-e67c-2b98-75d8c32efa50.png)

`SUMMARIZE`関数でも同じものがかける。

```
EVALUATE
SUMMARIZE (
    Sales,
    'Product'[Brand],
    'Product'[Category],
    "SalesAmt",
        SUMX (
            Sales,
            Sales[Net Price] * Sales[Quantity]
        )
)
ORDER BY [SalesAmt] DESC
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/b73856d3-9ed3-ae1e-49c9-e76e392fd6ca.png)

同じ結果がでている。

# 入れ子になったグループ化

これから掲載するコード、長くて見にくいかもしれませんが、Dax.doで作成しています。DAX.doのコード入力画面にいれて実行すれば同じ結果がでますので、ご活用ください💪

https://dax.do/

```
EVALUATE
ADDCOLUMNS (
    SUMMARIZE (
        ADDCOLUMNS (
            SUMMARIZE ( Product, 'Product'[Category], 'Product'[Subcategory] ),
            "Average Price", CALCULATE ( AVERAGE ( Product[Unit Price] ) )
        ),
        'Product'[Category]
    ),
    "Max SubCat Avg Price", CALCULATE ( MAX ( [Average Price] ) )
)
```

これを実行すると、エラーとなる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/020c4802-5e8d-ee0f-8bcd-51c761a7088c.png)

**DAXは物理的な列だけを集計できるため**、DAX内で作成した列の集計はできない。

## 修正

```
EVALUATE
ADDCOLUMNS (
    VALUES ( 'Product'[Category] ),
    "Max SubCat Avg Price",
        CALCULATE (
            MAXX (
                ADDCOLUMNS (
                    SUMMARIZE ( Product, 'Product'[Category], 'Product'[Subcategory] ),
                    "Average Price", CALCULATE ( AVERAGE ( Product[Unit Price] ) )
                ),
                [Average Price]
            )
        )
)
ORDER BY [Max SubCat Avg Price] DESC
```

こう書き直すと物理列の集計となり、正しい数字がでる。が、冗長であるのは否めない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/c13e553b-7acf-412e-9824-a671ce2dfc06.png)

## ここで`GROUPBY`関数

`CURRENTGROUP ()`関数を使うと、計算列にアクセスすることができるため、無事に計算をすることができる。

```
EVALUATE
GROUPBY (
    ADDCOLUMNS (
        GROUPBY (
            Product,
            'Product'[Category],
            'Product'[Subcategory]
        ),
        "Average Price", CALCULATE ( AVERAGE ( Product[Unit Price] ) )
    ),
    'Product'[Category],
    "Max SubCat Avg Price", MAXX ( CURRENTGROUP (), [Average Price] )
)
ORDER BY
[Max SubCat Avg Price] DESC
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/5d2c301d-b1b8-c334-21f3-91747e69ab72.png)

### 一番深いところの`GROUPBY`関数は`SUMMARIZE`関数に置換可能

```
EVALUATE
GROUPBY (
    ADDCOLUMNS (
        SUMMARIZE ( Product, 'Product'[Category], 'Product'[Subcategory] ),
        "Average Price", CALCULATE ( AVERAGE ( Product[Unit Price] ) )
    ),
    'Product'[Category],
    "Max SubCat Avg Price", MAXX ( CURRENTGROUP (), [Average Price] )
)
ORDER BY [Max SubCat Avg Price] DESC
```

結果は変わらない。

## `ADDCOLUMNS`関数を削除

`GROUPBY`関数とその集計列作成で使える`CURRENTGROUP`関数を使うと計算列にアクセスできるため、`ADDCOLUMNS`関数を削除することができる。ただし、メジャーを参照していたりする場合は`ADDCOLUMNS`関数を削除することはできない。（`CURRENTGROUP`関数を使ってメジャーの集計はできないため）

```
EVALUATE
GROUPBY (
    GROUPBY (
        Product,
        'Product'[Category],
        'Product'[Subcategory],
        "Average Price", AVERAGEX ( CURRENTGROUP (), Product[Unit Price] )
    ),
    'Product'[Category],
    "Max SubCat Avg Price", MAXX ( CURRENTGROUP (), [Average Price] )
)
ORDER BY
[Max SubCat Avg Price] DESC
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/e41b6604-a93a-583a-a48b-d5679f900c14.png)

# GROUPBY関数の使いどころ

イテレーターのグループ行にアクセスする場合は、`ADDCOLUMNS/SUMMARIZE`の代わりに`GROUPBY`関数を使用することもできます。ネストされたグループ化操作がある場合に必要となり、もっとも内側のグループでは`SUMMARIZE`関数を使用できますが、内側のグループ化関数で計算された列にアクセスするには、`GROUPBY`関数と`CURRENTGROUP `関数を使用する必要があります。

# 感想

もう一回書けと言われて、もう一回書ける自信はないけど、100回書いたら覚えられるかもって思えるきっかけにはなったかな😅つかいこなせば複雑な計算も思うがまま。頑張りましょう～💪