ISINSCOPEの動作について

この記事は[Microsoft Power BI Advent Calendar 2023](https://qiita.com/advent-calendar/2023/powerbi "Microsoft Power BI Advent Calendar 2023")に参加しています。
使用しているPower BIは2023/12/20時点の最新バージョンです。

# [ISINSCOPE]
[ISINSCOPE]は、指定した列がレベルの階層においてそのレベルである場合は True を返します。

**読んでも意味が分かりません。**

実際にどういう動きをするか見ていきましょう。

# 検証で利用するデータセット
Power BIの神[Takeshi Kagata](https://qiita.com/PowerBIxyz)さんが作成したサンドボックスのデータを利用させていただきました。
ファクトが1つ、ディメンションが4つのスタースキーマです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/3bb8b9ed-7928-0e4b-3f7a-d5bd99595084.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/a9f82d69-03af-8c62-1f1c-d168447ac44d.png)

## [ISINSCOPE]の検証
[ISINSCOPE]の動作を検証するために、ディメンションテーブルを[ISINSCOPE]の引数にしてみましょう。
今回利用する`Persons`テーブルは社員と所属のIDと、それぞれの表示名で構成されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/dfc4eaf8-faae-7ea3-4e51-88c5b07f43cd.png)

メジャーは以下の通りです。
```DAX:ISINSCOPE所属
ISINSCOPE所属 = ISINSCOPE(Persons[所属])
```
`Persons`テーブルから`所属`の列を[ISINSCOPE]の引数とします。
このメジャーをレポートページに置いただけでは`False`になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/4b7a6153-743d-99d1-1a11-24b1299b8963.png)


### スライサーの場合
所属のスライサーをページに追加して`大阪支社`を選択してみます。
`大阪支社`が選択されてもメジャーは`False`のままです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/93814e38-76e4-56d4-c740-597b7714af02.png)

### テーブルビジュアルに組み込んだ場合
所属とメジャーを同じテーブルビジュアルに組み込むと`True`になります。
この時、合計欄は`False`です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/6e2867dc-e8ba-7621-4fca-28e3c94459a6.png)

次に`Persons`テーブルから`所属`に加えて`氏名`列もテーブルビジュアルに組み込んでみます。
結果は前と変わりません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/3c8ad498-5ce7-da54-387d-a88ec54a423f.png)

最後にテーブルビジュアルから`所属`列を消してみます。
全て`False`になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/d738abd0-c366-d859-0337-04b73bc7bde1.png)

どうやら[ISINSCOPE]の引数にした`所属`列がカギのようです。

### マトリックスビジュアルに組み込んだ場合
マトリックスビジュアルで所属を行に、メジャーを値に組み込むと`True`になります。
この時、合計欄は`False`です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/9ea4e125-9e53-e73b-db1f-98de84d08232.png)

次に`Persons`テーブルから`所属`に加えて`氏名`列もマトリックスビジュアルに組み込んでみます。
`所属`の下の階層に`氏名`を置きました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/1274f891-37b2-3148-7177-8d7a6ac1ff53.png)

行が`所属`の階層を表示している場合、結果は前と変わりません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/b17443ae-36b3-ebef-9e7e-0dcb51547959.png)

`氏名`の階層まで展開しても合計欄以外は全て`True`です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/f0ecdc97-0e96-2c89-a58d-a85292d268fb.png)

`所属`と`氏名`の階層を逆にしてみましょう。
`所属`が表示されている行以外は全て`False`になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/13037255-48bc-1e66-3545-0a863a16cca3.png)

最後に`氏名`を列に移したらどうなるでしょうか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/9ce52be2-0e1c-21d2-5109-e7311d4d93c2.png)

`Persons`テーブルで`所属`と`氏名`が一致しているセルだけ`True`になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/46188482-3ec3-f812-e856-f10b5e39a6e1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/eeb0baf7-6338-d34c-35e6-8847ea27af0e.png)

## [ISINSCOPE]の動き
ここまでの結果では、[ISINSCOPE]の引数にした`Persons`テーブルの`所属`列がビジュアルに含まれている場合にだけメジャーが`True`になりました。
今までの結果を踏まえた上で、改めて[ISINSCOPE]の説明を見てみましょう。

[ISINSCOPE]は、指定した列がレベルの階層においてそのレベルである場合は TRUE を返します。

テーブルビジュアルでは全ての行に`所属`列が含まれており、合計欄以外は`True`です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/e762b767-141e-7bb7-ea2a-ae367f4e67a2.png)

マトリックスビジュアルでは行に階層があり、下の階層は上の階層に含まれます。
つまり`所属`の下に`氏名`を置いた場合、`氏名`は上の階層である`所属`に含まれるので合計欄以外は`True`です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/7ea8559e-c8d6-5301-b8ad-44bae2be3c88.png)

逆に`氏名`を上の階層に置いた場合、`所属`まで階層を展開しないと`True`が出てきません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/f73e72b8-0b0a-5025-26a2-cfea25223947.png)

最後に`氏名`をマトリックスビジュアルの列に置いた場合ですが、これは行の`所属`と列の`氏名`によるクロス集計です。
`Persons`テーブルに存在する`所属`と`氏名`の組み合わせは`True`になり、以外は`Blank`になりました。
そして`所属`を置いた行の小計は全て`True`、`氏名`を置いた列と総計欄は`False`です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/385f59e4-7a06-58b8-cd52-7034fbd96150.png)

これらの結果から「指定した列がレベルの階層においてそのレベルである場合は TRUE を返します」をもう少しかみ砕くと、「**[ISINSCOPE]の引数にした列が含まれた階層またはセルであれば`True`を返します**」とでも言えるのかなと思います。

## 何故合計欄は全て`False`なのか
Power BIにおいて、メジャーは基本的に総計で計算されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/9990f1f4-f6f1-3f67-1887-7c68ad9a7d34.png)

これにDAX式やビジュアルでフィルターをかけることで、ディメンション単位で個々の値を表示することが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/7a46d843-db8f-dec5-4f1f-b0fe43d0b7ec.png)

しかし合計欄はビジュアル内のフィルターから独立しているので、[ISINSCOPE]の引数にした列から影響を受けることはありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/43f728aa-7ade-818c-d565-d6818cef6cc0.png)

クロス集計の行の小計が`True`だったのは[ISINSCOPE]の引数にした列を行に置いたので、行レベルでは引数にした列によるフィルターが有効だったからです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/e797c590-7018-c58b-7e26-48fa8e675b4e.png)

### [SUMMARIZECOLUMNS]に組み込んだ場合
[SUMMARIZECOLUMNS]でテーブルを作成する際に、グループ化に使った列を[ISINSCOPE]の引数にしたらどうなるでしょうか？

[SUMMARIZECOLUMNS]で`所属`列をグループ化し、`所属`と`氏名`をそれぞれ[ISINSCOPE]の引数にした列を作成します。
メジャーは以下の通りです。
```DAX:ISINSCOPEでSUMMARIZECOLUMNSテーブル
ISINSCOPEでSUMMARIZECOLUMNSテーブル = SUMMARIZECOLUMNS('Persons'[所属],"ISINSCOPE所属列",ISINSCOPE(Persons[所属]),"ISINSCOPE氏名列",ISINSCOPE(Persons[氏名]))
```
これにより以下のようなテーブルが出来上がりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/07ac9ec3-4272-2dc4-362b-aad16c0d24f0.png)

[SUMMARIZECOLUMNS]で作成したテーブルにおいても、グループ化に使った列であれば[ISINSCOPE]が階層と認識していることが分かります。

# まとめ
### [ISINSCOPE]は引数で指定した列を含んだビジュアル、もしくは引数で指定した列でグループ化した[SUMMARIZECOLUMNS]で動く
引数がcolumnNameなので、条件式と組み合わせて使うことになります。
### 階層によって挙動が違う
上位に下位は含まれる原則は[ISINSCOPE]でも変わりません。
***
フィルターの状況に応じて動くDAX関数は[ISINSCOPE]の他にも[FILTERS]、[HASONEFILTER]、[HASONEVALUE]、[ISCROSSFILTERED]、[ISFILTERED]等があります。
これらの関数はDAX式がどう動いているかを勉強するのにとても役立つので、是非触ってみてください。

[ISFILTERED]については[去年記事を書きました](https://qiita.com/Yellow11/items/e24772199bf63796666f)ので興味があればどうぞご覧ください。

[ISFILTERED]:https://learn.microsoft.com/ja-jp/dax/isfiltered-function-dax
[REMOVEFILTERS]:https://learn.microsoft.com/ja-jp/dax/removefilters-function-dax
[FILTERS]:https://learn.microsoft.com/ja-jp/dax/filters-function-dax
[HASONEFILTER]:https://learn.microsoft.com/ja-jp/dax/hasonefilter-function-dax
[HASONEVALUE]:https://learn.microsoft.com/ja-jp/dax/hasonevalue-function-dax
[ISCROSSFILTERED]:https://learn.microsoft.com/ja-jp/dax/iscrossfiltered-function-dax
[ISINSCOPE]:https://learn.microsoft.com/ja-jp/dax/isinscope-function-dax
[SUMMARIZECOLUMNS]:https://learn.microsoft.com/ja-jp/dax/summarizecolumns-function-dax