7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DAXクエリで学ぶマトリックス構築 ― 第3回 タイムインテリジェンス

7
Last updated at Posted at 2025-12-22

1 なぜタイムインテリジェンスが重要か

ビジネスの世界では、数字を「時間軸」で比較することが日常的に行われている。

「今月の売上は先月より増えたのか?」
「今年の累計は去年の同時期と比べてどうか?」
「直近3ヶ月の平均はどう推移しているか?」

これらの問いに答えるには、単純な集計だけでは不十分である。「前年同期」「年初来累計」「移動平均」といった、時間に関連した複雑な計算が必要になる。

DAXには、こうした時間軸での計算を簡潔に記述するための専用関数群が用意されている。これをタイムインテリジェンス関数と呼ぶ。

タイムインテリジェンス関数の本質は、Filter Contextの中の「日付」を操作することである。第2回で学んだCALCULATEが「Filter Contextを変更する」関数だったことを思い出してほしい。タイムインテリジェンス関数は、CALCULATEと組み合わせて「日付のFilter Contextを特定のパターンで変更する」ための道具なのである。

今回使用するサンプルデータは、第1回・第2回と同じAdventureWorks Salesである。

2 日付テーブル:タイムインテリジェンスの土台

2.1 日付テーブルとは何か

タイムインテリジェンス関数を使う前に、まず「日付テーブル」について理解する必要がある。

通常、売上データには「注文日」や「出荷日」といった日付列が含まれている。しかし、この日付列をそのままタイムインテリジェンス関数に使うことには問題がある。

問題1:日付の欠損

売上テーブルには、売上があった日のデータしか存在しない。日曜定休の店舗であれば日曜日のレコードはなく、年末年始の休業期間もデータがない。この「穴」があると、「前月の売上」を計算しようとしたとき、正しい結果が得られないことがある。

問題2:属性の不足

「この日付は何年の第何四半期か」「何曜日か」「会計年度ではどの期に属するか」といった情報は、日付の値だけからは直接得られない。これらの属性がないと、「四半期ごとの集計」や「曜日別の分析」ができない。

問題3:粒度の制御

売上テーブルの日付列は、あくまで「トランザクションの属性」である。時間軸での分析を行うには、「時間」そのものを表すマスターテーブルが必要である。

これらの問題を解決するのが日付テーブル(Date Table、Calendar Table) である。

2.2 日付テーブルの要件

DAXのタイムインテリジェンス関数が正しく動作するには、日付テーブルが以下の要件を満たす必要がある。

要件1:連続した日付

分析対象期間のすべての日付が、1行ずつ存在すること。2023年1月1日から2023年12月31日までを分析するなら、その間の365日すべてが含まれていなければならない。土日祝日も、売上がゼロの日も、すべて含める。

要件2:重複なし

各日付は1回だけ出現すること。同じ日付が2行以上あってはならない。

要件3:年全体をカバー

タイムインテリジェンス関数の多くは「年」を単位として動作する。そのため、分析対象の各年について、1月1日から12月31日まで(または会計年度の開始日から終了日まで)の全日付が含まれている必要がある。

要件4:Date型の列

日付を格納する列は、文字列型ではなくDate型(またはDateTime型)でなければならない。

2.3 日付テーブルの構造

典型的な日付テーブルは、以下のような構造を持つ。

列名 説明
Date 日付(主キー) 2023-04-15
Year 2023
Month 月(数値) 4
MonthName 月名 April
Quarter 四半期 Q2
DayOfWeek 曜日(数値) 7
DayName 曜日名 Saturday
IsWeekend 週末フラグ TRUE
FiscalYear 会計年度 FY2023
FiscalQuarter 会計四半期 FQ1

これらの属性列は、集計やフィルタリングに活用される。

日本向け日付テーブル構造

列名 説明
Date 日付(主キー) 2023-04-15
Year 年(西暦) 2023
Month 月(数値) 4
MonthName 月名(日本語) 4月
Quarter 四半期(暦年) Q2
DayOfWeek 曜日(数値、日曜=1) 7
DayName 曜日名(日本語) 土曜日
IsWeekend 週末フラグ TRUE
FiscalYear 会計年度 FY2023 または 2023年度
FiscalQuarter 会計四半期 FQ1
FiscalYearQuarter 会計年度+四半期 FY2023-FQ1
YearMonth 年月(ソート用) 202304
YearMonthName 年月(表示用) 2023年4月
Wareki 和暦 令和5年
IsHoliday 祝日フラグ FALSE
HolidayName 祝日名 (空白)または 昭和の日
IsBusinessDay 営業日フラグ TRUE

官公庁や一部の企業では和暦が必要な場合があります。

日本固有の祝日(振替休日含む)をマスタ管理する必要があります。祝日は法改正で変わることがあるため、年次でメンテナンスが必要です。

2.4 日付テーブルの作成方法

日付けテーブルが未作成の場合、以下の手順で作成します。

方法1:DAXで計算テーブルを作成(推奨)

ステップ1:ベーステーブルの作成

Power BI Desktopで「モデリング」→「新しいテーブル」を選択し、以下を入力:

Date = CALENDAR(DATE(2021, 1, 1), DATE(2025, 12, 31))

ステップ2:計算列の追加

作成したDateテーブルに、以下の計算列を順次追加する。

// 年(西暦)
Year = YEAR('Date'[Date])

// 月(数値)
Month = MONTH('Date'[Date])

// 月名(日本語)
MonthName = FORMAT('Date'[Date], "M月")

// 四半期(暦年)
Quarter = "Q" & QUARTER('Date'[Date])

// 曜日(数値:日曜=1)
DayOfWeek = WEEKDAY('Date'[Date], 1)

// 曜日名(日本語)
DayName = FORMAT('Date'[Date], "aaaa", "ja-JP" )

// 週末フラグ
IsWeekend = IF(WEEKDAY('Date'[Date], 2) >= 6, TRUE, FALSE)

// 会計年度(4月始まり)
FiscalYear = 
IF(
    MONTH('Date'[Date]) >= 4,
    "FY" & YEAR('Date'[Date]),
    "FY" & (YEAR('Date'[Date]) - 1)
)

// 会計四半期(4月始まり)
FiscalQuarter = 
"FQ" & 
SWITCH(
    TRUE(),
    MONTH('Date'[Date]) IN {4, 5, 6}, 1,
    MONTH('Date'[Date]) IN {7, 8, 9}, 2,
    MONTH('Date'[Date]) IN {10, 11, 12}, 3,
    4
)

// 会計年度+四半期
FiscalYearQuarter = 'Date'[FiscalYear] & "-" & 'Date'[FiscalQuarter]

// 年月(ソート用)
YearMonth = YEAR('Date'[Date]) * 100 + MONTH('Date'[Date])

// 年月(表示用)
YearMonthName = FORMAT('Date'[Date], "YYYY年M月")

// 和暦
Wareki = 
VAR Y = YEAR('Date'[Date])
VAR M = MONTH('Date'[Date])
VAR D = DAY('Date'[Date])
VAR DateNum = Y * 10000 + M * 100 + D
RETURN
SWITCH(
    TRUE(),
    DateNum >= 20190501, "令和" & (Y - 2018) & "年",
    DateNum >= 19890108, "平成" & (Y - 1988) & "年",
    DateNum >= 19261225, "昭和" & (Y - 1925) & "年",
    "対象外"
)

ステップ3:日付テーブルとしてマーク

  1. Dateテーブルを選択
  2. 「テーブルツール」→「日付テーブルとしてマーク」
  3. Date列を日付列として指定

方法2:一括定義(計算テーブル)

すべての列を一度に定義する方法:

Date = 
VAR BaseCalendar = CALENDAR(DATE(2021, 1, 1), DATE(2025, 12, 31))
RETURN
ADDCOLUMNS(
    BaseCalendar,
    "Year", YEAR([Date]),
    "Month", MONTH([Date]),
    "MonthName", FORMAT([Date], "M月"),
    "Quarter", "Q" & QUARTER([Date]),
    "DayOfWeek", WEEKDAY([Date], 1),
    "DayName", FORMAT([Date], "aaaa", "ja-JP" ),
    "IsWeekend", IF(WEEKDAY([Date], 2) >= 6, TRUE, FALSE),
    "FiscalYear", IF(MONTH([Date]) >= 4, "FY" & YEAR([Date]), "FY" & (YEAR([Date]) - 1)),
    "FiscalQuarter", "FQ" & SWITCH(TRUE(), MONTH([Date]) IN {4,5,6}, 1, MONTH([Date]) IN {7,8,9}, 2, MONTH([Date]) IN {10,11,12}, 3, 4),
    "YearMonth", YEAR([Date]) * 100 + MONTH([Date]),
    "YearMonthName", FORMAT([Date], "YYYY年M月")
)

祝日の追加

日本の祝日は、移動祝日(成人の日など)、振替休日、法改正による変更があり、ルールベースでの自動生成は困難である。

推奨方法:内閣府の公式データを使用

内閣府が公開している祝日データ( https://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html )を年1回(1月頃)にデータを更新する。法改正や特例(オリンピック等)があれば随時対応する。政府公式データのため正確で、振替休日・国民の休日も含まれている。

年末年始やお盆休みなど企業独自の休業日は、祝日テーブルとは別に「会社カレンダー」テーブルで管理する。

リレーションシップの設定

日付テーブルとファクトテーブル(Salesなど)を接続:

  1. モデルビューを開く
  2. Date[Date] から Sales[OrderDate] へドラッグ
  3. リレーションシップが作成される(多対一)

注意点

項目 推奨事項
期間の範囲 分析対象期間 + 前後数年の余裕を持たせる
年全体をカバー 各年の1月1日〜12月31日を含める
重複なし 各日付は1行のみ
データ型 Date列は必ずDate型
日付テーブルとしてマーク タイムインテリジェンス関数の正常動作に必須

会計年度が4月始まりであっても、日付テーブルは1月1日から12月31日の暦年ベースで作成する。

3 累計の計算:TOTALxTD関数群

3.1 累計とは何か

ビジネスレポートでは「累計」が頻繁に登場する。累計とは、ある基準日から現在の日付までの合計値のことである。

最もよく使われるのは年初来累計(Year-To-Date、YTD) である。これは、その年の1月1日から現在の日付までの売上合計を意味する。

例えば、2023年4月の売上レポートを見ているとき

  • 「4月の売上」:4月1日〜4月30日の売上
  • 「年初来累計」:1月1日〜4月30日の売上

累計は、年間目標に対する進捗を把握したり、前年同期と比較したりするのに不可欠な指標である。

3.2 TOTALYTD:年初来累計

DAXでは、TOTALYTD関数を使って年初来累計を簡単に計算できる。

構文

TOTALYTD(
    <計算する式>,
    <日付列>,
    [<追加のフィルタ>],
    [<年度終了日>]
)

基本例

DEFINE
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    MEASURE Sales[YTD Sales] =
        TOTALYTD (
            [Sales Amount],
            'Date'[Date]
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Sales", FORMAT([Sales Amount], "$#,#0"),
    "YTD Sales", FORMAT([YTD Sales], "$#,#0")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

このクエリを実行すると、各月の売上と、その月時点での年初来累計が表示される。

image.png

3.3 TOTALYTDの動作原理

TOTALYTDは内部で何をしているのだろうか。実は、この関数は以下のCALCULATE式と等価である。

MEASURE Sales[YTD Sales Manual] =
    CALCULATE (
        [Sales Amount],
        DATESYTD('Date'[Date])
    )

DATESYTD関数は、現在のFilter Contextにある日付を見て、「その年の1月1日から、Filter Context内の最後の日付まで」の日付セットを返す。

つまり、Filter Contextが「2023年4月」のとき

  1. DATESYTDは「2023年1月1日〜2023年4月30日」の日付セットを返す
  2. CALCULATEがこの日付セットでFilter Contextを置き換える
  3. [Sales Amount]がこの新しいFilter Contextで評価される
  4. 結果として、1月から4月までの売上合計が返る

TOTALYTDは、この一連の処理を1つの関数にまとめたものである。このように、複雑な処理を簡潔に書けるようにした関数を糖衣構文(シンタックスシュガー) と呼ぶ。

3.4 年が変わるとリセットされる

累計の重要な特性は、「年が変わるとリセットされる」ことである。

2022年1月になると、YTD Salesは2022年1月の売上だけになる。これは、DATESYTDが「その年の1月1日から」という範囲を返すためである。

3.5 TOTALMTD と TOTALQTD

年初来だけでなく、月初来と四半期初来の累計も同様に計算できる。

TOTALMTD(Month-To-Date):月初来累計

MEASURE Sales[MTD Sales] =
    TOTALMTD (
        [Sales Amount],
        'Date'[Date]
    )

日単位でレポートを見るとき、「今月これまでの売上」を表示するのに使う。

TOTALQTD(Quarter-To-Date):四半期初来累計

MEASURE Sales[QTD Sales] =
    TOTALQTD (
        [Sales Amount],
        'Date'[Date]
    )

四半期ごとに業績を管理している企業で、四半期目標に対する進捗を把握するのに使う。

3.6 3つの累計を並べて確認

DEFINE
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    MEASURE Sales[MTD Sales] =
        TOTALMTD (
            [Sales Amount],
            'Date'[Date]
        )
    MEASURE Sales[QTD Sales] =
        TOTALQTD (
            [Sales Amount],
            'Date'[Date]
        )
    MEASURE Sales[YTD Sales] =
        TOTALYTD (
            [Sales Amount],
            'Date'[Date]
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Sales", FORMAT([Sales Amount], "$#,#0"),
    "MTD", FORMAT([MTD Sales], "$#,#0"),
    "QTD", FORMAT([QTD Sales], "$#,#0"),
    "YTD", FORMAT([YTD Sales], "$#,#0")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

image.png

月単位でグループ化しているため、MTDとSalesは同じ値になる(月全体がFilter Contextに含まれているため)。日単位でグループ化すれば、MTDの累積効果が見える。

4 前年同期比較:時間を遡る

4.1 前年比較の重要性

ビジネスでは「前年同期比」が最も重視される比較指標の一つである。

なぜ「前月比」ではなく「前年同期比」なのか。それは、多くのビジネスに季節性があるからである。小売業であれば12月は繁忙期、2月は閑散期といった具合に、月によって売上水準が大きく異なる。

2月の売上を1月と比較しても、季節性の影響で正しい評価ができない。しかし、去年の2月と比較すれば、同じ季節条件での成長を測ることができる。

4.2 SAMEPERIODLASTYEAR:前年同期

SAMEPERIODLASTYEARは、現在のFilter Contextにある日付を「1年前」にシフトした日付セットを返す関数である。

DEFINE
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    MEASURE Sales[PY Sales] =
        CALCULATE (
            [Sales Amount],
            SAMEPERIODLASTYEAR('Date'[Date])
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Sales", FORMAT([Sales Amount], "$#,#0"),
    "PY Sales", FORMAT([PY Sales], "$#,#0")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

image.png

4.3 SAMEPERIODLASTYEARはDATEADDのシンタックスシュガー

SAMEPERIODLASTYEARは、実は別の関数の省略形である。以下の2つは完全に同じ動作をする

SAMEPERIODLASTYEAR('Date'[Date])
DATEADD('Date'[Date], -1, YEAR)

SAMEPERIODLASTYEARは、DATEADDを「-1年」という固定パラメータで呼び出すシンタックスシュガーなのである。コードの意図が明確になるため、前年比較にはSAMEPERIODLASTYEARを使うことが推奨される。

4.4 前年比(YoY Growth)の計算

前年同期の値が取得できれば、成長率を計算できる。

DEFINE
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    MEASURE Sales[PY Sales] =
        CALCULATE (
            [Sales Amount],
            SAMEPERIODLASTYEAR('Date'[Date])
        )
    MEASURE Sales[YoY Growth] =
        VAR CurrentSales = [Sales Amount]
        VAR PreviousSales = [PY Sales]
        RETURN
        DIVIDE (
            CurrentSales - PreviousSales,
            PreviousSales
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Sales", FORMAT([Sales Amount], "$#,#0"),
    "PY Sales", FORMAT([PY Sales], "$#,#0"),
    "YoY Growth", FORMAT([YoY Growth], "+#0.0%;-#0.0%")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

成長率の計算式は「(今年 - 前年) / 前年」である。DIVIDE関数を使うことで、前年がゼロの場合のエラーを回避している。

image.png

4.5 前年累計比較(YTD YoY)

「今年の年初来累計」と「去年の同時期の年初来累計」を比較することも一般的である。

例えば、2023年4月時点で

  • 今年のYTD:2023年1月〜4月の累計
  • 去年のYTD:2022年1月〜4月の累計

この比較により、「同じ時期までの進捗」を比べることができる。

DEFINE
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    MEASURE Sales[YTD Sales] =
        TOTALYTD (
            [Sales Amount],
            'Date'[Date]
        )
    MEASURE Sales[PY YTD Sales] =
        CALCULATE (
            [YTD Sales],
            SAMEPERIODLASTYEAR('Date'[Date])
        )
    MEASURE Sales[YTD YoY Growth] =
        DIVIDE (
            [YTD Sales] - [PY YTD Sales],
            [PY YTD Sales]
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "YTD Sales", FORMAT([YTD Sales], "$#,#0"),
    "PY YTD Sales", FORMAT([PY YTD Sales], "$#,#0"),
    "YTD YoY", FORMAT([YTD YoY Growth], "+#0.0%;-#0.0%")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

ここでのポイントは、SAMEPERIODLASTYEARを[YTD Sales]メジャーに対して適用していることである。これにより、「去年の同じ月時点でのYTD」が計算される。

image.png

5 DATEADD:汎用的な期間シフト

5.1 DATEADDの構文

DATEADDは、タイムインテリジェンスの中核となる汎用関数である。

DATEADD(
    <日付列>,
    <移動数>,
    <期間の種類>
)

期間の種類

  • DAY:日単位でシフト
  • MONTH:月単位でシフト
  • QUARTER:四半期単位でシフト
  • YEAR:年単位でシフト

移動数

  • 負の数:過去へシフト
  • 正の数:未来へシフト

5.2 DATEADDの動作アルゴリズム(重要)

DATEADDの動作は、期間の種類によって異なるアルゴリズムを使用する。これを理解することが、タイムインテリジェンスを正しく使いこなす鍵となる。

DAYの場合

すべての日付を指定日数分シフトする。月末の扱いでは、シフト先の月に該当日が存在しない場合、その月の最終日が返される。

MONTH、QUARTER、YEARの場合

DATEADDは、入力された日付を「月単位」で分析する。

  1. 月全体が選択されている場合:その月全体をシフトする
  2. 月の一部だけが選択されている場合:各日付を個別にシフトする

この区別が重要である。例えば、2月(28日)全体が選択されているとき、DATEADDで1ヶ月前にシフトすると、1月全体(31日)が返される。月の日数の違いを自動的に考慮してくれるのである。

-- 2月全体(28日)から1ヶ月シフト → 1月全体(31日)が返る
DATEADD('Date'[Date], -1, MONTH)

一方、2月の一部(例:2月1日〜2月15日)だけが選択されている場合は、各日付が個別に1ヶ月シフトされ、1月1日〜1月15日が返される。

5.3 DATEADDの使用例

前年同期(SAMEPERIODLASTYEARと等価)

MEASURE Sales[PY Sales] =
    CALCULATE (
        [Sales Amount],
        DATEADD('Date'[Date], -1, YEAR)
    )

前月

MEASURE Sales[PM Sales] =
    CALCULATE (
        [Sales Amount],
        DATEADD('Date'[Date], -1, MONTH)
    )

前四半期

MEASURE Sales[PQ Sales] =
    CALCULATE (
        [Sales Amount],
        DATEADD('Date'[Date], -1, QUARTER)
    )

2年前

MEASURE Sales[2Y Ago Sales] =
    CALCULATE (
        [Sales Amount],
        DATEADD('Date'[Date], -2, YEAR)
    )

5.4 前月比較(MoM)の実装

DEFINE
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    MEASURE Sales[PM Sales] =
        CALCULATE (
            [Sales Amount],
            DATEADD('Date'[Date], -1, MONTH)
        )
    MEASURE Sales[MoM Growth] =
        DIVIDE (
            [Sales Amount] - [PM Sales],
            [PM Sales]
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Sales", FORMAT([Sales Amount], "$#,#0"),
    "PM Sales", FORMAT([PM Sales], "$#,#0"),
    "MoM Growth", FORMAT([MoM Growth], "+#0.0%;-#0.0%")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

前月比は季節性の影響を受けるため、YoYほど一般的ではないが、短期的なトレンドを把握するのに有用である。

image.png

5.5 DATEADDの誤解

多くの人がDATEADDを「日付に年月日を足し引きする関数」と誤解している。SQLやExcelのDATEADD関数がそのように動作するためである。

SQLやExcelのDATEADD

単一の日付値を受け取り、単一の日付値を返す。

-- SQL Server
DATEADD(month, -1, '2023-04-15')  -- 結果: 2023-03-15
-- Excel
=EDATE(A1, -1)  -- 1ヶ月前の日付

DAXのDATEADD

DAXのDATEADDは全く異なる。テーブル(日付の列) を受け取り、テーブル(日付のセット) を返す。

項目 SQL/ExcelのDATEADD DAXのDATEADD
入力 単一の日付値 日付列(テーブル)
出力 単一の日付値 日付のセット(テーブル)
用途 日付の計算 Filter Contextの操作
使い方 単独で使用 CALCULATEと組み合わせ

単純な日付計算をしたい場合

DAXで単純な日付計算(1年前の日付値を取得)をするには、DATE関数を使う。

-- 単一の日付値から1年前を計算
VAR OneYearAgo = DATE(YEAR([Date]) - 1, MONTH([Date]), DAY([Date]))

または

-- 計算列で使用
Previous Year Date = EDATE('Date'[Date], -12)

6 PARALLELPERIOD:完全な期間を返す

6.1 PARLLELPERIODの動作原理

PARALLELPERIODは、DATEADDとは異なるアルゴリズムで動作する。

PARLLELPERIODは、入力された日付に「少なくとも1日でも含まれている期間」を検出し、その期間全体をシフトして返す。

例えば、入力が「2019年2月1日〜3月10日」の場合

  • MONTH指定:2月と3月に日付が含まれているので、シフト先も2ヶ月分が返る
  • QUARTER指定:Q1に日付が含まれているので、シフト先も四半期全体が返る
  • YEAR指定:2019年に日付が含まれているので、シフト先も年全体が返る

重要 PARALLELPERIODはDAY指定をサポートしていない。

6.2 DATEADDとPARALLELPERIODの違い

両者の違いは、「年レベル」で見ると同じに見えるが、「月レベル」で見ると明確になる。

DEFINE
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    MEASURE Sales[DATEADD -1Y] =
        CALCULATE (
            [Sales Amount],
            DATEADD('Date'[Date], -1, YEAR)
        )
    MEASURE Sales[PARALLELPERIOD -1Y] =
        CALCULATE (
            [Sales Amount],
            PARALLELPERIOD('Date'[Date], -1, YEAR)
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Sales", FORMAT([Sales Amount], "$#,#0"),
    "DATEADD", FORMAT([DATEADD -1Y], "$#,#0"),
    "PARALLELPERIOD", FORMAT([PARALLELPERIOD -1Y], "$#,#0")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

結果の違い

image.png

  • DATEADD:各月に対して「前年の同じ月」を返す(2022年5月 → 2021年5月)
  • PARALLELPERIOD:「前年全体」を返す(2022年のどの月でも → 2021年全体)

この違いは重要である。DATEADDは「同じ粒度で比較」、PARALLELPERIODは「完全な期間と比較」という異なる用途を持つ。

6.3 使い分けの指針

DATEADDを使う場面

  • 前年同月、前月、前四半期など「同じ粒度」での比較
  • 日付の範囲をそのままシフトしたい場合
  • SAMEPERIODLASTYEARの代わり(より柔軟なパラメータ指定が必要な場合)

PARALLELPERIODを使う場面

  • 「前年全体」「前四半期全体」など完全な期間が必要な場合
  • 入力の粒度に関係なく、特定の期間全体を取得したい場合

なお、以下の様に記述すれば、先のPARALLELPERIODを使って同じ結果を出すことが出来る。

    MEASURE Sales[PARALLELPERIOD -1Y] =
        CALCULATE (
            [Sales Amount],
            PARALLELPERIOD('Date'[Date], -12, MONTH)
        )

image.png

ただし、日単位でフィルタされている場合は結果が異なる。動作の意味を理解することが重要。

7 PREVIOUS系・NEXT系関数

7.1 PREVIOUS系関数の構造

DAXには、「前の期間」を取得する専用関数がある。

  • PREVIOUSDAY:前日
  • PREVIOUSMONTH:前月
  • PREVIOUSQUARTER:前四半期
  • PREVIOUSYEAR:前年

これらの関数は、内部的にPARALLELPERIODとFIRSTDATEを組み合わせて実装されている。

-- 以下は等価
PREVIOUSMONTH('Date'[Date])
PARALLELPERIOD(FIRSTDATE('Date'[Date]), -1, MONTH)

PREVIOUSYEAR('Date'[Date])
PARALLELPERIOD(FIRSTDATE('Date'[Date]), -1, YEAR)

FIRSTDATEが使われるため、入力に複数の期間が含まれていても、最初の日付を基準にした単一の期間のみが返される。これがPARALLELPERIODとの重要な違いである。

7.2 PREVIOUSYEARとPARALLELPERIODの違い

この違いは、特に「合計行」で顕著になる。

DEFINE
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    MEASURE Sales[PREVIOUSYEAR] =
        CALCULATE (
            [Sales Amount],
            PREVIOUSYEAR('Date'[Date])
        )
    MEASURE Sales[PARALLELPERIOD -1Y] =
        CALCULATE (
            [Sales Amount],
            PARALLELPERIOD('Date'[Date], -1, YEAR)
        )

VAR DetailRows =
    SUMMARIZECOLUMNS (
        'Date'[Year],
        "Sales", [Sales Amount],
        "PREVIOUSYEAR", [PREVIOUSYEAR],
        "PARALLELPERIOD", [PARALLELPERIOD -1Y]
    )

VAR TotalRow =
    ROW (
        "Year", "Total",
        "Sales", CALCULATE([Sales Amount], ALL('Date')),
        "PREVIOUSYEAR", CALCULATE([PREVIOUSYEAR], ALL('Date')),
        "PARALLELPERIOD", CALCULATE([PARALLELPERIOD -1Y], ALL('Date'))
    )

EVALUATE
UNION(DetailRows, TotalRow)
ORDER BY [Year]

image.png

合計行での動作の違い

合計行では、Filter Contextに複数年が含まれる。

  • PREVIOUSYEAR:最初の年(例:2007年)の前年を探すが、2006年がDateテーブルに存在しないためBLANKを返す
  • PARALLELPERIOD:すべての年を1年シフトし、存在する範囲(2007〜2008年など)の合計を返す

この違いを理解していないと、レポートの合計行で予期しない結果になることがある。

7.3 NEXT系関数

PREVIOUS系の逆に、「次の期間」を返す関数もある。

  • NEXTDAY:翌日
  • NEXTMONTH:翌月
  • NEXTQUARTER:翌四半期
  • NEXTYEAR:翌年

これらは内部的にLASTDATEと正の数を使用する。

-- 以下は等価
NEXTMONTH('Date'[Date])
PARALLELPERIOD(LASTDATE('Date'[Date]), 1, MONTH)

予算や予測との比較、または過去データ分析時に「その時点での翌期実績」を見る場合に使う。

8 日付範囲を返す関数

8.1 DATESBETWEEN:絶対的な日付範囲

DATESBETWEENは、指定した開始日から終了日までの日付セットを返す。

DEFINE
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    -- 2008年第1四半期の売上(固定期間)
    MEASURE Sales[Q1 2024 Sales] =
        CALCULATE (
            [Sales Amount],
            DATESBETWEEN (
                'Date'[Date],
                DATE(2024, 1, 1),
                DATE(2024, 3, 31)
            )
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    "Total Sales", FORMAT([Sales Amount], "$#,#0"),
    "Q1 2024", FORMAT([Q1 2024 Sales], "$#,#0")
)
ORDER BY 'Date'[Year]

image.png

DATESBETWEENは「絶対的な」日付範囲を指定する。どのFilter Contextでも、常に同じ期間を返す。

8.2 DATESINPERIOD:相対的な日付範囲

DATESINPERIODは、基準日から相対的な期間を指定する。

DATESINPERIOD(
    <日付列>,
    <基準日>,
    <期間数>,
    <期間の種類>
)

例:直近3ヶ月

DEFINE
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    MEASURE Sales[Last 3 Months] =
        CALCULATE (
            [Sales Amount],
            DATESINPERIOD (
                'Date'[Date],
                MAX('Date'[Date]),  -- Filter Context内の最後の日付
                -3,
                MONTH
            )
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Sales", FORMAT([Sales Amount], "$#,#0"),
    "Last 3 Months", FORMAT([Last 3 Months], "$#,#0")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

image.png

この例では、MAX('Date'[Date])を基準日としている。これにより、Filter Context内の最後の日付から過去3ヶ月間の日付セットが返される。

DATESINPERIODは移動平均の計算に特に有用である。

9 移動平均の計算

9.1 移動平均とは

移動平均は、データの短期的な変動を平滑化し、トレンドを把握するための手法である。

例えば「3ヶ月移動平均」は、直近3ヶ月の平均値を計算する。毎月計算すると、この「窓」が1ヶ月ずつスライドしていく。

売上 3ヶ月移動平均
1月 100 -
2月 120 -
3月 110 110 (100+120+110)/3
4月 130 120 (120+110+130)/3
5月 90 110 (110+130+90)/3

9.2 DATESINPERIODを使った移動平均

DEFINE
    -- 売上金額:数量 × 単価 の合計
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )

    -- 3ヶ月移動平均
    MEASURE Sales[3M Moving Avg] =
        VAR TotalSales = 
            CALCULATE (
                [Sales Amount],
                -- 現在の最終日から過去3ヶ月間の日付セットでフィルタ
                DATESINPERIOD (
                    'Date'[Date],
                    MAX('Date'[Date]),
                    -3,
                    MONTH
                )
            )
        RETURN
        DIVIDE(TotalSales, 3)

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Sales", FORMAT([Sales Amount], "$#,##0"),
    "3M Avg", FORMAT([3M Moving Avg], "$#,##0")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

image.png

9.3 より正確な移動平均(月数を動的に計算)

上記の実装は「常に3で割る」が、データの最初の2ヶ月では3ヶ月分のデータがない。より正確な実装は、実際に存在する月数で割る。

DEFINE
    -- 売上金額:数量 × 単価 の合計
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )

    -- 3ヶ月移動平均(実際の月数で割る正確版)
    MEASURE Sales[3M Moving Avg Correct] =
        VAR Period =
            DATESINPERIOD (
                'Date'[Date],
                MAX('Date'[Date]),
                -3,
                MONTH
            )
        -- 期間内の実際の月数をカウント(データ開始時に3ヶ月未満の場合に対応)
        VAR MonthsInPeriod =
            CALCULATE (
                DISTINCTCOUNT('Date'[Month Number]),
                Period
            )
        -- 期間内の売上合計
        VAR TotalSales =
            CALCULATE (
                [Sales Amount],
                Period
            )
        RETURN
        -- 実際の月数で割る(データ不足時も正確な平均を算出)
        DIVIDE(TotalSales, MonthsInPeriod)

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Sales", FORMAT([Sales Amount], "$#,##0"),
    "3M Avg", FORMAT([3M Moving Avg Correct], "$#,##0")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

image.png

この実装では、期間内の売上合計を実際の月数で割っている。

10 半加算メジャー(Semi-Additive Measures)

10.1 半加算メジャーとは

ここまで扱ってきた「売上」は、単純に足し算できる加算メジャー(Additive Measure) である。1月の売上と2月の売上を足せば、1〜2月の売上になる。

しかし、すべての指標がこのように足し算できるわけではない。

例1:在庫数

1月末の在庫100個と2月末の在庫120個を足しても「1〜2月の在庫」にはならない。在庫は「ある時点での状態」を表す値であり、期間を通じた累積ではない。

例2:為替レート

1月のレート150円と2月のレート148円を足しても意味がない。期末時点のレートを使うべきである。

例3:累計ユニーク顧客数

1月に100人、2月に120人の顧客がいたとき、単純に足して220人とはならない。同じ顧客が両月で購入していれば重複するためである。

これらは半加算メジャー(Semi-Additive Measure) と呼ばれる。

10.2 半加算メジャーの特性

半加算メジャーには以下の特性がある:

集計軸 加算可否
時間軸 × 加算できない 1月の在庫 + 2月の在庫 ≠ 1〜2月の在庫
他の軸 ○ 加算できる A店舗の在庫 + B店舗の在庫 = 全店舗の在庫

そのため、時間軸での集計には特別な処理が必要である。

10.3 為替レートで理解する半加算メジャー

サンプルデータのSalesテーブルには為替レート(Exchange Rate)列がある。これを使って半加算メジャーの概念を確認する。

DEFINE
    -- 売上金額(加算メジャー:足し算できる)
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    
    -- 為替レートの単純平均(参考用)
    MEASURE Sales[Exchange Rate AVG] =
        AVERAGE(Sales[Exchange Rate])
    
    -- 期末の為替レート(半加算メジャー:期末値を使用)
    MEASURE Sales[Exchange Rate End] =
        CALCULATE (
            AVERAGE(Sales[Exchange Rate]),
            LASTDATE('Date'[Date])
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Sales", FORMAT([Sales Amount], "$#,##0"),
    "Rate AVG", FORMAT([Exchange Rate AVG], "0.000"),
    "Rate End", FORMAT([Exchange Rate End], "0.000")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

image.png

Rate AVG は月内の平均レート、Rate End は月末時点のレートを返す。為替換算では通常、期末レートを使うため Rate End が適切である。

10.4 LASTDATE:期間の最終日の値

LASTDATE は、Filter Context内の最後の日付だけを返すテーブル関数である。

-- LASTDATEの動作イメージ
-- Filter Contextが「2023年4月」の場合
LASTDATE('Date'[Date])  -- → 2023年4月30日のみを返す

これをCALCULATEと組み合わせることで、「期間の最終日の値」を取得できる。

10.5 累計ユニーク顧客数:足し算できない例

半加算メジャーのもう一つの典型例として、累計ユニーク顧客数がある。

DEFINE
    -- 当月の顧客数
    MEASURE Sales[Monthly Customers] =
        DISTINCTCOUNT(Sales[CustomerKey])
    
    -- 年初来の累計ユニーク顧客数
    MEASURE Sales[YTD Unique Customers] =
        CALCULATE (
            DISTINCTCOUNT(Sales[CustomerKey]),
            DATESYTD('Date'[Date])
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Monthly Customers", [Monthly Customers],
    "YTD Unique Customers", [YTD Unique Customers]
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

image.png

注目ポイント:

  • Monthly Customers の累計 ≠ YTD Unique Customers
  • 同じ顧客が複数月で購入しているため、単純な足し算より少なくなる
  • これが半加算メジャーの特性である

10.6 LASTNONBLANK:データがある最後の日

データが毎日記録されているとは限らない。週次や月次でしか記録されていない場合、LASTDATEではデータのない日を参照してしまう可能性がある。

LASTNONBLANK は、指定した式が値を返す最後の日付を見つける。

DEFINE
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    
    -- データが存在する最終日の売上
    MEASURE Sales[Last Day Sales] =
        CALCULATE (
            [Sales Amount],
            LASTNONBLANK(
                'Date'[Date],
                CALCULATE([Sales Amount])
            )
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Sales", FORMAT([Sales Amount], "$#,##0"),
    "Last Day Sales", FORMAT([Last Day Sales], "$#,##0")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

image.png

LASTDATEとLASTNONBLANKの違い:

関数 動作 使用場面
LASTDATE Filter Context内の最終日を返す データが毎日存在する場合
LASTNONBLANK データがある最終日を返す データに欠損がある場合

10.7 まとめ:半加算メジャーの判断基準

メジャーを設計する際、以下の質問で半加算メジャーかどうかを判断できる:

「1月の値と2月の値を足したものは、1〜2月の値として意味があるか?」

回答 メジャーの種類 時間軸の集計
はい 加算メジャー 売上、数量、コスト SUM、TOTALYTD
いいえ 半加算メジャー 在庫、残高、為替レート、ユニーク数 LASTDATE、LASTNONBLANK、DISTINCTCOUNT

半加算メジャーの扱いは複雑なため、要件に応じて適切な集計方法を選択する必要がある。

11 会計年度への対応

11.1 会計年度とは

多くの企業では、「会計年度」が暦年(1月〜12月)と異なる。

地域・業種 会計年度 年度終了日
日本の多くの企業 4月始まり 3月31日
米国の連邦政府 10月始まり 9月30日
小売業の一部 2月始まり 1月31日

タイムインテリジェンス関数は、デフォルトでは暦年(1月〜12月)を基準にしている。日本企業で使う場合、会計年度への対応が必要になる。

11.2 TOTALYTDでの会計年度設定

TOTALYTDには、第4引数で「年度終了日」を指定できる。

TOTALYTD(
    <式>,
    <日付列>,
    [<フィルタ>],
    [<年度終了日>]  -- "M/DD" または "MM/DD" 形式
)

4月始まり(3月31日終了)の場合:

DEFINE
    -- 売上金額
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    
    -- 暦年ベースの年初来累計(1月リセット)
    MEASURE Sales[Calendar YTD] =
        TOTALYTD (
            [Sales Amount],
            'Date'[Date]
        )
    
    -- 会計年度ベースの年初来累計(4月リセット)
    -- DATESYTDの第2引数で年度終了日を指定
    MEASURE Sales[Fiscal YTD] =
        CALCULATE (
            [Sales Amount],
            DATESYTD('Date'[Date], "3/31")
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Sales", FORMAT([Sales Amount], "$#,##0"),
    "Calendar YTD", FORMAT([Calendar YTD], "$#,##0"),
    "Fiscal YTD", FORMAT([Fiscal YTD], "$#,##0")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

image.png

11.3 会計年度での累計の動き

暦年YTDと会計年度YTDの違い:

Year Month Sales Calendar YTD Fiscal YTD 備考
2022 1 $1,000 $1,000 $10,000 Calendar YTDリセット
2022 2 $1,200 $2,200 $11,200
2022 3 $1,100 $3,300 $12,300
2022 4 $1,300 $4,600 $1,300 Fiscal YTDリセット
2022 5 $900 $5,500 $2,200

ポイント:

  • Calendar YTD:1月にリセット(暦年ベース)
  • Fiscal YTD:4月にリセット(会計年度ベース、3月末決算)

11.4 会計年度用の計算列

より柔軟な会計年度対応には、日付テーブルに会計年度関連の列を追加することを推奨する。これにより、SUMMARIZECOLUMNSで会計年度単位のグループ化が可能になる。

Power BIで以下の計算列を作成:

-- 会計年度(4月始まり)
-- 4月〜12月 → 当年、1月〜3月 → 前年
Fiscal Year = 
IF(
    MONTH('Date'[Date]) >= 4,
    "FY" & YEAR('Date'[Date]),
    "FY" & (YEAR('Date'[Date]) - 1)
)

-- 会計四半期(4月始まり)
-- 4-6月:FQ1、7-9月:FQ2、10-12月:FQ3、1-3月:FQ4
Fiscal Quarter = 
"FQ" & 
SWITCH(
    TRUE(),
    MONTH('Date'[Date]) IN {4, 5, 6}, 1,
    MONTH('Date'[Date]) IN {7, 8, 9}, 2,
    MONTH('Date'[Date]) IN {10, 11, 12}, 3,
    4
)

-- 会計年度+四半期(表示用)
Fiscal Year Quarter = 
[Fiscal Year] & "-" & [Fiscal Quarter]

暦年と会計年度の対応表(4月始まり):

暦年 暦年Quarter 会計年度 会計Quarter
2023年4月 2023 Q2 FY2023 FQ1
2023年7月 2023 Q3 FY2023 FQ2
2023年10月 2023 Q4 FY2023 FQ3
2024年1月 2024 Q1 FY2023 FQ4
2024年4月 2024 Q2 FY2024 FQ1

12 実務で使うパターン集

12.1 売上分析ダッシュボードの標準メジャーセット

実務では、以下のようなメジャーセットを標準的に作成することが多い。これらをテンプレートとして用意しておくと、新しいプロジェクトでも素早く分析を始められる。

DEFINE
    -- ========================================
    -- 基本メジャー
    -- ========================================
    MEASURE Sales[Sales Amount] =
        SUMX (
            Sales,
            Sales[Quantity] * Sales[Net Price]
        )
    
    -- ========================================
    -- 累計系(Year/Quarter/Month To Date)
    -- ========================================
    
    -- 年初来累計
    MEASURE Sales[YTD Sales] =
        TOTALYTD([Sales Amount], 'Date'[Date])
    
    -- 四半期初来累計
    MEASURE Sales[QTD Sales] =
        TOTALQTD([Sales Amount], 'Date'[Date])
    
    -- ========================================
    -- 前年比較(Year over Year)
    -- ========================================
    
    -- 前年同期の売上
    MEASURE Sales[PY Sales] =
        CALCULATE (
            [Sales Amount],
            SAMEPERIODLASTYEAR('Date'[Date])
        )
    
    -- 前年比成長率:(今年 - 前年) / 前年
    MEASURE Sales[YoY Growth %] =
        VAR CurrentSales = [Sales Amount]
        VAR PreviousSales = [PY Sales]
        RETURN
        DIVIDE(CurrentSales - PreviousSales, PreviousSales)
    
    -- 前年比差額:今年 - 前年
    MEASURE Sales[YoY Diff] =
        [Sales Amount] - [PY Sales]
    
    -- ========================================
    -- 前年累計比較(YTD Year over Year)
    -- ========================================
    
    -- 前年同期の年初来累計(正しい計算方法)
    MEASURE Sales[PY YTD Sales] =
        CALCULATE (
            [Sales Amount],
            DATESYTD(SAMEPERIODLASTYEAR('Date'[Date]))
        )
    
    -- 年初来累計の前年比成長率
    MEASURE Sales[YTD YoY Growth %] =
        DIVIDE([YTD Sales] - [PY YTD Sales], [PY YTD Sales])
    
    -- ========================================
    -- 前月比較(Month over Month)
    -- ========================================
    
    -- 前月の売上
    MEASURE Sales[PM Sales] =
        CALCULATE (
            [Sales Amount],
            DATEADD('Date'[Date], -1, MONTH)
        )
    
    -- 前月比成長率
    MEASURE Sales[MoM Growth %] =
        DIVIDE([Sales Amount] - [PM Sales], [PM Sales])
    
    -- ========================================
    -- 移動平均
    -- ========================================
    
    -- 3ヶ月移動平均
    MEASURE Sales[3M Moving Avg] =
        DIVIDE(
            CALCULATE(
                [Sales Amount], 
                DATESINPERIOD('Date'[Date], MAX('Date'[Date]), -3, MONTH)
            ),
            3
        )

EVALUATE
SUMMARIZECOLUMNS (
    'Date'[Year],
    'Date'[Month Number],
    "Sales", FORMAT([Sales Amount], "$#,##0"),
    "YTD", FORMAT([YTD Sales], "$#,##0"),
    "PY Sales", FORMAT([PY Sales], "$#,##0"),
    "YoY %", FORMAT([YoY Growth %], "+#0.0%;-#0.0%;-"),
    "YoY Diff", FORMAT([YoY Diff], "$+#,##0;$-#,##0;$0"),
    "MoM %", FORMAT([MoM Growth %], "+#0.0%;-#0.0%;-"),
    "3M Avg", FORMAT([3M Moving Avg], "$#,##0")
)
ORDER BY 'Date'[Year], 'Date'[Month Number]

12.2 メジャーセットの使い方

上記のメジャーは、以下のような分析シナリオで活用できる:

メジャー 主な用途
YTD Sales 年間目標に対する進捗確認
YoY Growth % 前年との成長比較(季節性を排除)
YoY Diff 前年との絶対額の差
PY YTD Sales 同時期までの累計比較
MoM Growth % 短期トレンドの把握
3M Moving Avg 変動を平滑化したトレンド分析

13 タイムインテリジェンス関数のまとめ

13.1 関数の分類と内部構造

多くのタイムインテリジェンス関数は、基本関数の**シンタックスシュガー(syntax sugar)**である。内部構造を理解すると、関数の動作を予測しやすくなる。

関数 内部実装 用途
TOTALYTD CALCULATE + DATESYTD 年初来累計
TOTALQTD CALCULATE + DATESQTD 四半期初来累計
TOTALMTD CALCULATE + DATESMTD 月初来累計
SAMEPERIODLASTYEAR DATEADD(..., -1, YEAR) 前年同期
PREVIOUSMONTH PARALLELPERIOD(FIRSTDATE(...), -1, MONTH) 前月全体
PREVIOUSQUARTER PARALLELPERIOD(FIRSTDATE(...), -1, QUARTER) 前四半期全体
PREVIOUSYEAR PARALLELPERIOD(FIRSTDATE(...), -1, YEAR) 前年全体
NEXTMONTH PARALLELPERIOD(LASTDATE(...), 1, MONTH) 翌月全体

13.2 使い分けの指針

分析要件 推奨関数 備考
年初来累計 TOTALYTD 会計年度は第4引数で指定
前年同月比 SAMEPERIODLASTYEAR DATEADDでも可
前月比 DATEADD(..., -1, MONTH)
前年全体との比較 PARALLELPERIOD(..., -1, YEAR) 年レベルで異なる動作
移動平均 DATESINPERIOD + CALCULATE MAX関数と組み合わせ
固定期間の抽出 DATESBETWEEN 絶対的な日付指定
会計年度累計 TOTALYTD + 第4引数 "3/31"など
在庫・残高(半加算) LASTDATE / LASTNONBLANK 期末値を取得

13.3 よくある間違いと解決方法

間違い1:日付テーブルがない、または不完全

タイムインテリジェンス関数を使う前に、以下を確認すること:

  • 日付テーブルが存在する
  • 「日付テーブルとしてマーク」されている
  • 1月1日〜12月31日の全日付が含まれている

間違い2:DATEADDとPARALLELPERIODの混同

関数 月単位フィルタ時 使い分け
DATEADD(..., -1, YEAR) 前年同月 同じ粒度での比較
PARALLELPERIOD(..., -1, YEAR) 前年全体 完全な期間との比較

間違い3:PREVIOUSYEARの合計行での動作

PREVIOUSYEARは内部でFIRSTDATEを使うため、複数年が選択されていると予期しない結果になる。合計行での動作を必ず確認すること。

間違い4:前年データがないときの処理

最初の年には前年データがないため、YoY計算がBLANKになる。必要に応じてIF文で処理を追加する。

-- 前年がない場合やゼロの場合を考慮した安全な計算
MEASURE Sales[YoY Growth Safe] =
    VAR Current = [Sales Amount]
    VAR Previous = [PY Sales]
    RETURN
    IF (
        ISBLANK(Previous) || Previous = 0,
        BLANK(),  -- または 0、"N/A" など
        DIVIDE(Current - Previous, Previous)
    )

間違い5:PY YTD Sales の計算式

以下の式は正しく動作しない場合がある:

-- 誤り:YTD Salesメジャー内のTOTALYTDとフィルタが干渉する
MEASURE Sales[PY YTD Sales Wrong] =
    CALCULATE (
        [YTD Sales],
        SAMEPERIODLASTYEAR('Date'[Date])
    )

正しい計算式:

-- 正しい:DATESYTDとSAMEPERIODLASTYEARを組み合わせる
MEASURE Sales[PY YTD Sales] =
    CALCULATE (
        [Sales Amount],
        DATESYTD(SAMEPERIODLASTYEAR('Date'[Date]))
    )

参考文献と学習リソース

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?