DAX workout - タイム インテリジェンス関数 - FIRSTDATE / LASTDATE

**失敗を減らすための仕草**
タイム インテリジェンス関数の`<dates>`パラメータには日付テーブルの日付列を使用する。

# Warm up
https://learn.microsoft.com/en-us/dax/firstdate-function-dax
```text:FIRSTDATE function (DAX)
FIRSTDATE(<dates>)
```
- 戻り値は 1列(日付列)の*テーブル*
- 戻り値は 2行以上にならない。
- 戻り値に含まれる値は`MINX( Dates, Dates[Date])`と同じ。

https://learn.microsoft.com/en-us/dax/lastdate-function-dax
```text:LASTDATE function (DAX)
LASTDATE(<dates>)
```
- 戻り値は 1列(日付列)の*テーブル*
- 戻り値は 2行以上にならない
- 戻り値に含まれる値は`MAXX( Dates, Dates[Date])`と同じ

# Workout-1
```text:DAX クエリ
EVALUATE
FIRSTDATE( Dates[Date] )
```
|Date|
|:--|
|2020-01-01|

日付テーブルの Date列(日付列)が 2020-01-01 からだから。

```text:DAX クエリ
EVALUATE
LASTDATE( Dates[Date] )
```
|Date|
|:--|
|2022-12-31|

日付テーブルの Date列(日付列)が 2022-12-31 までだから。

```text:DAX クエリ
EVALUATE
CALCULATETABLE(
	FIRSTDATE( Dates[Date] ),
	YEAR( Dates[Date] ) = 2021,
	MONTH( Dates[Date] ) = 7
)
```
|Date|
|:--|
|2021-07-01|
```text:DAX クエリ
EVALUATE
CALCULATETABLE(
	LASTDATE( Dates[Date] ),
	YEAR( Dates[Date] ) = 2021,
	MONTH( Dates[Date] ) = 7
)
```
|Date|
|:--|
|2021-07-31|

```text:DAX クエリ
EVALUATE
CALCULATETABLE(
	FIRSTDATE( Dates[Date] ),
	Dates[Date] = dt"2021-07-15"
)
```
```text:DAX クエリ
EVALUATE
CALCULATETABLE(
	LASTDATE( Dates[Date] ),
	Dates[Date] = dt"2021-07-15"
)
```
いずれのクエリも同じ結果(テーブル)を返した。
|Date|
|:--|
|2021-07-15|

```text:DAX クエリ
EVALUATE
{
	ISEMPTY(
		CALCULATETABLE(
			FIRSTDATE( Dates[Date] ),
			YEAR( Dates[Date] ) = 2000
		)
	)
}
```
```text:DAX クエリ
EVALUATE
{
	ISEMPTY(
		CALCULATETABLE(
			LASTDATE( Dates[Date] ),
			YEAR( Dates[Date] ) = 2000
		)
	)
}
```
いずれのクエリも同じ結果を返した。
|Value|
|:--|
|True|

日付テーブルに含まれる日付には2000年の日付が含まれていないから。

# Workout-2
**戻り値がテーブルである。**
**戻り値がテーブルだからCALCULATE 関数の *`<filter>`* パラメータで使用する。**
```text:DAX クエリ
EVALUATE
SUMMARIZECOLUMNS(
	Dates[Year],
	"Sales amount FirstDate",
	CALCULATE(
		[Sales amount],
		FIRSTDATE( Dates[Date] )
	)
)

ORDER BY
	Dates[Year]
```
日付テーブルに含まれる日付の各Dates[Year]ごとでもっとも過去の日付で評価される  

```text:DAX クエリ
EVALUATE
SUMMARIZECOLUMNS(
	Dates[Year],
	"Sales amount LastDate",
	CALCULATE(
		[Sales amount],
		LASTDATE( Dates[Date] )
	)
)

ORDER BY
	Dates[Year]
```
日付テーブルに含まれる日付の各Dates[Year]ごとでもっとも最新の日付で評価される  

# Workout-3

```text:期待しない結果になる例 : 戻り値をスカラ値として使用する。
EVALUATE
SUMMARIZECOLUMNS(
	Dates[Year],
	"Sales amount",
	VAR _Date = FIRSTDATE( Dates[Date] )	// ❌
//	VAR _Date = LASTDATE( Dates[Date] )		// ❌
	RETURN
	CALCULATE(
		[Sales amount],
		Dates[Date] = _Date					// ❌
	)
)

ORDER BY
	Dates[Year]
```
```text:よくない例 : 日付テーブル以外の日付時刻列で使う。
EVALUATE
SUMMARIZECOLUMNS(
	Dates[Year],
	"Sales amount",
	CALCULATE(
		[Sales amount],
		FIRSTDATE( Sales[受注日] )			// ❌
	)
)

ORDER BY
	Dates[Year]
```
# Workout-4
MINX / MIN / MAXX / MAX との動作の違いを知る。
SE(Storage engine)で 集計する/集計しない の違いがあるんだぜ。
- 日付テーブル以外の日付時刻列で FIRSTDATE / LASTDATE 関数を使わない理由
- 日付テーブルの日付列でも FIRSTDATE / LASTDATE 関数を使わないときもある理由
***
```text:DAX クエリ
EVALUATE
FIRSTDATE( Dates[Date] )
```
```sql:Import(xmSQL)
SET DC_KIND="AUTO";
SELECT
'Dates'[Date]
FROM 'Dates';
```
```sql:DirectQuery(T-SQL)
SELECT 
TOP (1000001) [t1].[Date]
FROM [Dates] AS [t1]
GROUP BY [t1].[Date] 
```
***
```text:DAX クエリ
EVALUATE
{ MIN( Dates[Date] ) }
```
```sql:Import(xmSQL)
-- メタデータから取得
```
```sql:DirectQuery(T-SQL)
SELECT MIN([t1].[Date])
 AS [a0]
FROM [Dates] AS [t1] 
```
***
```text:DAX クエリ
EVALUATE
{
	CALCULATE(
		MIN( Dates[Date] ),
		Dates[Date] <= dt"9999-12-31"
	)
}
```
```sql:Import(xmSQL)
SET DC_KIND="AUTO";
SELECT
MIN ( 'Dates'[Date] )
FROM 'Dates'
WHERE
	 ( PFCASTCOALESCE ( 'Dates'[Date] AS  REAL ) <= COALESCE ( 2958465.000000 )  ) ;
```
```sql:DirectQuery(T-SQL)
SELECT MIN([t1].[Date])
 AS [a0]
FROM [Dates] AS [t1]
WHERE 
([t1].[Date] <= CAST( '9999-12-31 00:00:00' AS datetime))
```

# Workout-5
**Context transition**
FIRSTDATE / LASTDATE (タイム インテリジェンス関数)の *`<dates>`* パラメータに日付列を使用するときにはコンテキストトランジションが発生する。`CALCULATETABLE( DISTINCT( Dates[Date] ) )`

```text:DAX クエリ
EVALUATE
ADDCOLUMNS(
    Dates,
    "LastDate", LASTDATE( Dates[Date] ),
    "MaxDate",
        MAXX(
            Dates,
            Dates[Date]
        ),
    "Calculate_MaxDate",
        CALCULATE(
            MAXX(
                Dates,
                Dates[Date]
            )
        )
)
```
LastDate 列と MaxDate 列は同じ評価結果にはならない。


# 思ったこと🙄
同じ結果が得られるからといって、なんでもよいというわけではない。
記述したメジャーが含まれる DAX クエリで最善を探るとよい。
動作について知ることがスタート地点。
# その他
https://powerbi.connpass.com/

- [Power BI 勉強会 - connpass](https://powerbi.connpass.com/)
- [Power BI Desktop を使い始めるには](http://qiita.com/PowerBIxyz/items/6c4735cb5b5712e70981)
- [Excel で Power Query を使い始めるには](http://qiita.com/PowerBIxyz/items/52e563037b855a099ca9)