(Power BI) DAXの変数


# DAXの変数
　DAXで変数を使う場合、以下のような形で書けます。

```java
VAR 変数名 = 式
RETURN
    戻り値
```
　宣言された変数のスコープを閉じるには、RETURNステートメントが必要です。
　RETURNで閉じられるまで、複数の宣言を行うことができます。
　変数は一度だけ割り当てることができ、再割り当てはできません。
　Power Queryの評価モデルは遅延評価が適用されるものが多いので、変数は値を保存しているのではなく、中身はオブジェクト（式）です。最終的に計算されるかどうかは、全体の評価の中で決まります。

```java:変数を使った例
Measure = 
VAR One = 1
RETURN
    One // 結果は１になります
```

```java:複数の変数を使った例
Measure = 
VAR One = 1
VAR Two = 2
-- VAR One = One + 1  // 再割り当てはエラーになります
RETURN 
    Tne + Two
```

　変数の設定は、順番が関係あります。

```java:後に設定されている変数は使用できません
Measure = 
VAR One = Two // エラーになります。
VAR Two = 2
RETURN 
    Tne + Two
```

```java:入れ子になった変数
Nesting =
VAR One = 0
VAR Num1 = 10
VAR Num2 =
    VAR One = One + 1 // 外側の変数はオーバーライドできます
    VAR Two = 2
    RETURN
        One + Two // Num2は3になります。
RETURN
    Num1 + Num2 // 結果は13になります
    -- Num1 + Num2 + Two // エラーになります。入れ子になった内側の変数は参照できません
    -- One // 結果は0になります。内側で変更されても外側に影響を与えません
```

# 変数が有効な理由
- 複雑さを軽減
- デバッグが容易
- 読みやすさの向上
- パフォーマンスの向上

　DAXは、関数の中で関数を使うような形で表現され、複雑さが上がると、非常に読みにくくなります。変数を使うと、人にも機械にもやさしい表現になることがあります。

　以下のメジャーは、次の計算を求めます。
 $売り上げ前年比 = \frac{今年の売り上げ - 昨年の売り上げ}{昨年の売り上げ}$

```java:変数を使わない例
Sales YoY% =
DIVIDE (
    SUM ( financials[ Sales] )
        - CALCULATE (
            SUM ( financials[ Sales] ),
            SAMEPERIODLASTYEAR ( financials[Date] )
        ),
    CALCULATE (
        SUM ( financials[ Sales] ),
        SAMEPERIODLASTYEAR ( financials[Date] )
    )
)
```

```java:変数を使った例
Sales YoY% M = 
VAR PrevSales =
    CALCULATE ( 
        SUM(financials[ Sales]), 
        SAMEPERIODLASTYEAR ( financials[Date] ) 
    )
RETURN
    DIVIDE ( 
        SUM(financials[ Sales]) - PrevSales, 
        PrevSales 
    )
```

　計算の中で昨年の売り上げが２回使用されますが、変数を使うと１回の記述で済みます。また、一度計算して変数に入れたものを使えば、複数回同じ処理をせずに済みますので、複雑なメジャーであれば、パフォーマンスも向上します。

　変数の名前を見れば、何の値を計算しているか理解しやすく、デバッグもしやすくなります。以下のように、RETURNの値を変えて、正しく計算されているかステップ・バイ・ステップで確認することもできます。

```java:RETURNを変更
Sales YoY% M = 
VAR PrevSales =
    CALCULATE ( 
        SUM(financials[ Sales]), 
        SAMEPERIODLASTYEAR ( financials[Date] ) 
    )
RETURN
    PrevSales
    -- DIVIDE ( [Sales] - PrevSales, PrevSales )
```
　DAXでは、**//**、**--**、**/* */**を使って、コメントアウトすることができます。DAXエディターでは、**Ctrl + /** で、選択範囲をコメントアウトすることができます。（[Power BI Desktop のキーボード ショートカット](https://docs.microsoft.com/ja-jp/power-bi/create-reports/desktop-accessibility-keyboard-shortcuts#dax-editor))

# フィルターコンテキスト

　フィルターコンテキストに変数を使う場合、注意が必要です。

```java
Pct =
DIVIDE (
    SUM ( financials[ Sales] ),
    CALCULATE (
        SUM ( financials[ Sales] ),
        ALLSELECTED ( financials[Product] )
    )
)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/de56a8b8-ae8f-36b7-4259-dd1f9d236291.png)

　上記のメジャーを、以下のように書き換えると、正しく動作しません。

```java:間違い
Pct =
VAR sales = SUM ( financials[ Sales] )
RETRN
DIVIDE (
    SUM ( financials[ Sales] ),
    CALCULATE (
        sales,
        ALLSELECTED ( financials[Product] )
    )
)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/165c0588-efaf-25df-43d5-6be1b96fd934.png)

　**CALCULATE**の第１引数の式は、第２引数のフィルターで評価されますが、変数が使われることで、事前に値が決まってしまい、フィルタが適用されません。

# メジャーと計算列の変数
　メジャーと計算列では、変数の書き方が変わります。
　計算列は、行単位で計算を行いますので、以下のような書き方になります。

```java:計算列
Profit CC =
financials[Units Sold] * financials[Sale Price] - financials[Discounts] - financials[COGS]
```

　変数を無理やり使って書き換えてみました。

```java:計算列
Profit CC =
VAR GrossSales = financials[Units Sold] * financials[Sale Price]
VAR Sales = GrossSales - financials[Discounts]
VAR Profit = Sales - financials[COGS]
RETURN
    Profit
```

　一方、メジャーでは、フィルターコンテキストが働きますので、以下のようになります。

```java:メジャー
Profit M = 
SUMX(
    financials,
    financials[Units Sold] * financials[Sale Price] - financials[Discounts] - financials[COGS]
)
```

　これを、計算列にならって変数を使って書き換えてみます。

```java:メジャー
Profit M =
VAR GrossSales =
    SUMX ( financials, financials[Units Sold] * financials[Sale Price] )
VAR Sales =
    GrossSales - SUM ( financials[Discounts] )
VAR Profit =
    Sales - SUM ( financials[COGS] )
RETURN
    Profit
```
　以下のような書き方はダメです。

```java:メジャーよくない例
Profit M = 
VAR UnitsSold = SUM(financials[Units Sold])
VAR SalePrice = SUM(financials[Sale Price])
VAR GrossSales = UnitsSold * SalePrice
VAR Sales = GrossSales - SUM(financials[Discounts])
VAR Profit = Sales - SUM(financials[COGS])
RETURN
    Profit
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/691092e9-50d0-9449-7305-fce1b009202d.png)

　無理やり感がありますが、関数の中に書くという書き方もできます。

```java:メジャー
Profit M = 
VAR GrossSales = 
    SUMX(
        financials,
        VAR UnitsSold = financials[Units Sold]
        VAR SalePrice = financials[Sale Price]
        RETURN
            UnitsSold * SalePrice
    )
VAR Sales = GrossSales - SUM(financials[Discounts])
VAR Profit = Sales - SUM(financials[COGS])
RETURN
    Profit
```