Power BIのDAXは、セマンティックモデルの上で集計の定義を書くための数式言語です。Excelの関数に似た見た目ですが、セルではなく列とテーブルを相手にし、スライサーやビジュアルの絞り込みに合わせて結果が変わります。この記事では、メジャーと計算列のどちらに書くかの判断、Power BI Desktopでメジャーを作ってDAXクエリビューで確かめる手順、CALCULATEとフィルターコンテキスト、日付テーブルと前年比・年累計のメジャー、ユーザー定義関数までを、貼り付けて動かせるコードで示します。仕様の根拠は2026年11月時点のMicrosoft Learnの記述です。
まとめ:Power BIのDAXはメジャー中心で書き、CALCULATEと日付テーブルを先に固める
集計値はメジャーに書き、計算列は行ごとに値が決まり、スライサーの軸やリレーションシップのキーに使う列だけに絞ります。計算列は更新のたびに全行を計算してモデルに保存するため、増やすほど更新時間とファイルサイズが伸びます。
DAXで最初に身につけるのはCALCULATEです。構成比、条件付きの売上、前年比のほとんどが「フィルターを外す・足す・ずらす」の組み合わせで書けます。前年比や年累計を出す前に、欠けている日付の無い日付テーブルを1本用意してください。書いたメジャーはレポート上で目視せず、DAXクエリビューで数字を並べて確かめてからモデルに保存します。
DAXの数式を書く場所と、メジャー・計算列・計算テーブルの使い分け
DAXの式は、メジャー、計算列、計算テーブル、行レベルセキュリティの規則の4か所に書けます。業務で迷うのは前の2つです。
メジャーと計算列で計算のタイミングと保存先が変わる仕組みと選び方
計算列の解説ページによると、計算列は新しい列のDAX数式に対してテーブル内のすべての行の結果を計算し、基になるデータが更新されたときに再計算されます。メジャーはモデルに値を持たず、ビジュアルが表示されるたびに、その時点の絞り込みで計算されます。
| 観点 | メジャー | 計算列 |
|---|---|---|
| 計算するとき | ビジュアルの表示時 | データの更新時(インポート) |
| 値の保存 | 保存しない | 全行をモデルに保存 |
| スライサーへの反応 | 反応する | 行ごとに固定 |
| 主な用途 | 売上合計・構成比・前年比 | 区分・ランク・結合キー |
判断は1問で足ります。「その値はスライサーで絞り込まれたときに変わるべきか」。変わるべきならメジャー、行ごとに固定でよく、凡例や軸に置きたいなら計算列です。顧客を年間購入額で「高・低」に分ける区分は、スライサーの軸に使うので計算列にします。
計算列が更新時間とモデルサイズを押し上げる条件とPower Queryへ移す判断
同じページの表では、インポートモードの計算列は「具体化」され、更新時に値を求める仕組みです。DirectQueryの計算列は具体化されず、クエリのたびに計算されます。インポートでは更新が遅くなり、DirectQueryでは表示が遅くなるという、どちらでも費用のかかる作りです。
計算列の式が同じテーブルの列だけで完結するなら、Power Queryのカスタム列に移したほうが取り込み時に一度で済みます。[City] & "," & [State]のような文字列の連結や、日付から年月を切り出す処理は、Power Query側に置く候補です。DAXに残すべきなのは、別テーブルの集計値を参照する区分のように、モデルのリレーションシップを使わないと書けない列だけです。
Power BI DesktopでDAXのメジャーを作り、DAXクエリビューで検証する手順
メジャーの作成自体は数クリックです。手間が掛かるのは、正しい数字が出ているかを確かめる工程のほうです。
新しいメジャーの作成からホームテーブル・表示フォルダーで整理するまで
メジャーの解説ページに沿うと、作成と整理は次の順です。
- [モデリング]タブの[新しいメジャー]を選び、数式バーに
売上合計 = SUM ( 'Sales'[SalesAmount] )のように入力する - メジャーの[ホームテーブル]で、[データ]ペインのどのテーブルの下に表示するかを選ぶ
- モデルビューの[プロパティ]ペインで[表示フォルダー]に名前を入れ、関連するメジャーをまとめる
- [データの入力]で1列だけのテーブルを作り、メジャーをそこへ移してから列を非表示にする
表示フォルダーは、バックスラッシュで区切るとサブフォルダーになり、セミコロンで区切ると1つのメジャーを複数のフォルダーに出せます。手順4のメジャー専用テーブルは[データ]ペインの最上部に表示されるため、メジャーが数十本に増えても探しやすくなります。
DAXクエリビューのDEFINE MEASUREで複数メジャーを試してからモデルへ保存
DAXクエリビューでは、DEFINE MEASUREで書いたメジャーはそのクエリの中だけで動く「クエリスコープのメジャー」になります。レポートに表を置かずに、複数のメジャーを並べた結果の確認が可能です。Desktopの左側のDAXクエリビューのアイコンから開き、次のクエリを貼って[実行]を押します。
DEFINE
/// 税抜の売上合計。返品は含まない
MEASURE 'Sales'[売上合計] = SUM ( 'Sales'[SalesAmount] )
/// 注文1件あたりの平均売上
MEASURE 'Sales'[注文単価] =
DIVIDE ( [売上合計], DISTINCTCOUNT ( 'Sales'[OrderKey] ) )
EVALUATE
SUMMARIZECOLUMNS (
'Product'[Category],
"売上合計", [売上合計],
"注文単価", [注文単価]
)
ORDER BY [売上合計] DESC
表名と列名は自社のモデルに合わせて置き換えてください。結果が意図どおりなら、MEASUREの行の上に出る「モデルの更新: 新しいメジャーの追加」をクリックするとモデルに保存されます。既にあるメジャーと式が違えば「メジャーの上書き」に変わり、まとめて保存するならコマンドバーの[変更を反映してモデルを更新]を使う流れです。///で書いた行は、メジャーの説明として一緒に保存されます。
結果グリッドには上限があり、1クエリあたり15MB、値は100万個までです。20列のクエリなら5万行で止まります。Webの同じ画面は最大99,999行で、セマンティックモデルへの書き込み権限が必要です。DesktopとServiceの役割の違いはPower BI DesktopとServiceの違いと発行・更新の手順で整理しています。
CALCULATEとフィルターコンテキストで構成比・条件付き集計を書くコード例
DAXが難しいと言われる理由の大半は、同じ式が置かれた場所によって違う値を返すことにあります。仕組みは2種類の「コンテキスト」で説明できます。
行コンテキストとフィルターコンテキストの違いとコンテキスト遷移が起きる場面
フィルターコンテキストは、ビジュアルの行見出し、スライサー、ページのフィルターによって「いま計算対象になっている行の集合」です。行コンテキストは、計算列やSUMXのような反復関数の中で「いま見ている1行」を指し、それ自体は何も絞り込みません。
この2つをつなぐのがコンテキスト遷移です。CALCULATEのリファレンスには、フィルター引数なしのCALCULATEは行コンテキストをフィルターコンテキストに切り替える、と書かれています。計算列でSUM ( 'Sales'[SalesAmount] )とだけ書くと全行が同じ総売上になるのに、CALCULATE ( SUM ( 'Sales'[SalesAmount] ) )と包むとその顧客の売上になるのはこのためです。行コンテキストの中でメジャーを呼んだ場合は、遷移が自動で起きます。
REMOVEFILTERSで構成比、KEEPFILTERSで条件付き売上を書くメジャー例
CALCULATEはCALCULATE ( 式, フィルター1, フィルター2, … )の形で、フィルター引数のとおりに絞り込みを変えてから式を計算します。同じ列に既にフィルターがある場合は、新しいフィルターによる上書きが基本の動作です。実務で多い3パターンを並べます。
// 1. カテゴリ別の売上構成比(Categoryの絞り込みだけ外して分母にする)
売上構成比 =
DIVIDE (
[売上合計],
CALCULATE ( [売上合計], REMOVEFILTERS ( 'Product'[Category] ) )
)
// 2. オンライン経由の売上(既存のChannelの絞り込みを残したまま条件を足す)
オンライン売上 =
CALCULATE ( [売上合計], KEEPFILTERS ( 'Sales'[Channel] = "Online" ) )
// 3. 全期間・全カテゴリの売上(日付とProductの絞り込みをすべて外す)
全体売上 =
CALCULATE ( [売上合計], REMOVEFILTERS ( 'Date' ), REMOVEFILTERS ( 'Product' ) )
2つ目でKEEPFILTERSを付けないと、スライサーで「店舗」を選んでいてもChannel = "Online"で上書きされ、オンラインの数字が出続けます。ALLでもフィルターは外せますが、リファレンスはツールが対応していればREMOVEFILTERSを使うよう勧めています。
ブール式のフィルター引数には制限があります。参照できるのは1つのテーブルの列だけで、メジャーは書けず、CALCULATEの入れ子も使えません。DirectQueryモードでは、CALCULATEを計算列と行レベルセキュリティの規則の中で使えない点も、設計の段階で確認してください。
FILTER関数をフィルター引数に使ってよい場面と、ブール式で書くべき場面
入門記事でよく見るCALCULATE ( [売上合計], FILTER ( 'Product', 'Product'[Color] = "Red" ) )は、正しい結果を返しますが遅い書き方です。FILTERをフィルター引数に使わないためのガイドでは、インポートのテーブルは列単位で絞り込むよう作られたメモリ内の列ストアなので、KEEPFILTERS ( 'Product'[Color] = "Red" )のようなブール式で渡すよう推奨しています。
FILTERが要るのは、ブール式で書けない条件のときだけです。具体的には、条件にメジャーを含む場合(利益が出た月だけの売上など)、別の列どうしを比べる場合、ORで複数の列をまたぐ場合の3つです。それ以外でFILTERを見つけたら、ブール式に書き直す候補として扱います。
タイムインテリジェンス関数で前年比と年累計を出す日付テーブルの準備
前年比、年累計、前月比はタイムインテリジェンス関数で書きます。どの関数も、日付が欠けずに並んだテーブルを前提にしています。
日付テーブルとしてマークする条件と、CALENDARで日付テーブルを作るDAX
Power BI Desktopは、日付の列ごとに非表示の日付テーブルを自動で作ります。小さなモデルでは便利ですが、日付列が増えるほどモデルが膨らみます。時間ベースの計算の解説に載っている日付テーブルのDAXを、日本の会計年度向けに列を足して書き直したのが次の式です。[モデリング]タブの[新しいテーブル]に貼ります。
Date =
ADDCOLUMNS (
CALENDAR ( DATE ( 2020, 1, 1 ), DATE ( 2027, 12, 31 ) ),
"年", YEAR ( [Date] ),
"月", MONTH ( [Date] ),
"年月", FORMAT ( [Date], "YYYY-MM" ),
// 4月始まりの会計年度(2026年4月〜2027年3月を2026年度とする)
"会計年度", IF ( MONTH ( [Date] ) >= 4, YEAR ( [Date] ), YEAR ( [Date] ) - 1 ),
"曜日番号", WEEKDAY ( [Date], 2 )
)
作ったテーブルを右クリックし、[日付テーブルとしてマークする]を選びます。日付テーブルの設定ページによると、マーク時に値が一意か、nullが無いか、始めから終わりまで連続しているか、日付時刻型なら全行のタイムスタンプが同じかを検証します。マークすると自動作成の日付テーブルは削除され、それを参照していたビジュアルとDAXは動かなくなるため注意が必要です。既存のレポートがある場合は、マークの前に日付の軸を新しいテーブルの列へ差し替えてください。最後に、売上テーブルの日付列と'Date'[Date]をリレーションシップでつなぎます。
日付テーブルを使った前年比・年累計のメジャーと変数・除算関数の記述例
日付テーブルができれば、前年比と年累計は数行です。以下はTOTALYTD・SAMEPERIODLASTYEARとVAR・DIVIDEを組み合わせたメジャーの記述例です。会計年度の年累計は、TOTALYTDの最後の引数に年度末を「月/日」の文字列で渡します。既定値は12月31日です。
// 前年同期の売上
前年売上 =
CALCULATE ( [売上合計], SAMEPERIODLASTYEAR ( 'Date'[Date] ) )
// 前年比(前年が無い期間は空白を返す)
前年比 =
VAR _前年 = [前年売上]
RETURN
DIVIDE ( [売上合計] - _前年, _前年 )
// 4月始まり・3月末締めの年度累計
年度累計売上 =
TOTALYTD ( [売上合計], 'Date'[Date], "3/31" )
前年比でVARを使うのは、前年売上を一度だけ計算させるためです。変数のベストプラクティスでは、同じ前年比の式を変数に置き換えると、クエリの時間が約半分になったと説明されています。RETURN _前年に一時的に書き換えれば、途中の値だけを確かめるデバッグにも使えます。
割り算は/ではなくDIVIDEで書きます。DIVIDEと除算演算子の比較によると、分母が0か空白のときDIVIDEは空白を返し、空白のグループはビジュアルから自動で消えます。分母が定数のときだけ、演算子のほうが速いというのが同ページの説明です。
会計年度4月始まりと週単位の集計で、カレンダーベースのプレビューを使う条件
Microsoft Learnの同じページは、2026年11月時点でカレンダーベースのタイムインテリジェンス(プレビュー)を推奨しています。日付テーブルに「年」「月」「週」などの列の役割をカレンダーとして登録し、TOTALYTD ( [売上合計], '会計カレンダー' )のように列ではなくカレンダー名を渡す方式です。クラシックの関数には週単位の計算が無く、日付に欠けがあるとエラーになりますが、カレンダー方式は週の関数を持ち、欠けた日付のままでも動きます。
有効にするには、Desktopの[ファイル]>[オプションと設定]>[オプション]>[プレビュー機能]で[拡張 DAX タイム インテリジェンス]を選び、Desktopを再起動します。ただし、Power BI Serviceではカレンダーを作れず、ライブ接続と複合モデルでは使えず、カレンダーを使う関数どうしの入れ子も書けません。本番のレポートで4月始まりの年度と月次だけを扱うなら、一般提供の機能である上のクラシックの書き方で足ります。4-4-5の小売カレンダーや週次の累計が要るときに限って、検証用のファイルで試してから移すのが安全です。
同じ計算式の重複を減らすDAXユーザー定義関数の定義と保存の手順
税込金額、前年比、粗利率のような式を何本ものメジャーに書き写していると、税率や定義が変わったときに直し漏れが出ます。2026年11月時点では、この重複をDAXのユーザー定義関数(UDF)で1か所にまとめられます。
DEFINE FUNCTIONで税込金額や前年比を関数にする書き方と互換性レベル1702
ユーザー定義関数のページには、UDFはデータベース互換性レベル1702以上が必要で、2026年6月のリリース時点でPower BI DesktopとServiceで一般公開されていると書かれています。DAXクエリビューで次のように定義して試します。
DEFINE
/// 税抜金額を受け取り、税込金額を返す(税率の既定は10%)
FUNCTION AddTax = ( amount : NUMERIC, taxRate : NUMERIC = 0.1 ) =>
amount * ( 1 + taxRate )
/// 当期と比較対象を受け取り、増減率を返す(比較対象が0や空白なら空白)
FUNCTION ChangeRate = ( current : NUMERIC, base : NUMERIC ) =>
DIVIDE ( current - base, base )
EVALUATE
{ ( AddTax ( 1000 ), AddTax ( 1000, 0.08 ), ChangeRate ( 120, 100 ) ) }
// 1100, 1080, 0.2 が返る
結果を確かめたら、[変更を反映してモデルを更新]で関数をモデルに保存し、メジャーから前年比 = ChangeRate ( [売上合計], [前年売上] )のように呼び出します。指定できるパラメーターの数は0〜256個です。上の例は既定のval(呼び出す前に評価)で、CALCULATEの中で評価のタイミングを関数側に任せたい場合はexprを指定します。
制限もあります。UDFは表示フォルダーに入れられず、再帰と同名関数のオーバーロードは使えません。関数名とパラメーター名に使えるのは英数字とアンダースコアで、関数名だけはピリオドで名前空間を区切れます(例:Finance.AddTax)。メジャー名は日本語で付けられますが、関数名は英語で付ける前提で命名規則を決めてください。
DAXを社内で書き続けてよい体制と、モデル設計から外部に任せる目安
DAXの関数を覚えれば、メジャーは誰でも書けるようになります。数字が合わなくなる原因は、関数の知識よりもモデルの作りと命名の管理にあります。
メジャーが100本を超える前に命名規則とメジャー専用テーブルを決めておく理由
社内で書き続けてよいのは、次の条件がそろう体制です。売上・粗利・件数などの基本メジャーを1か所で定義し、他のメジャーはそれを参照していること。日付テーブルが1本で、全ファクトがそれにつながっていること。メジャーの名前と説明に「税抜」「返品除く」のような定義が書かれていることです。この状態なら、担当者が替わってもDAXクエリビューの「このモデル内のすべてのメジャーを定義」で全式を一覧でき、引き継げます。
逆に、レポートごとに別のモデルを作り、同じ「売上」が税込と税抜で混在している組織では、DAXを書き足すほど数字の食い違いが増えます。この状態でメジャーを追加するのはやめ、先に基本メジャーと日付テーブルを1本にまとめ直してください。用語をモデル全体でそろえる考え方はセマンティックレイヤーの仕組みと導入判断で解説しています。
DAXの修正が止まらないモデルをBI導入支援に任せるときの作業範囲
外部に任せる目安は3つあります。複数の業務システムのデータを1本のモデルに統合し直すとき。前年比や構成比の数字が部門ごとに合わず、定義をそろえる調整役がいないとき。レポートの表示が遅く、計算列とFILTERの書き換えから手を付けたいときです。
モデルの棚卸しからメジャーの再設計、日付テーブルの統一までを1つの作業として進めるなら、BIツール導入支援で現在のレポートとモデルの構成を確認したうえで、残すメジャーと書き直す順番を決められます。
Power BIのDAXの書き方・関数・エラーについてよくある質問
DAXを書き始めた段階でつまずきやすい点に、Microsoft Learnの記述をもとに答えます。
DAXとExcelの関数は何が違いますか?
SUMやIF、DATEなど同じ名前の関数は多くありますが、対象が違います。Excelはセル単位で行ごとに別の数式を書けますが、DAXの対象は列とテーブルであり、計算列なら全行に同じ式を適用する仕組みです。メジャーはスライサーやビジュアルの絞り込みに合わせて結果が変わるため、Excelの感覚でセル参照を探すと行き詰まります。DAXには200を超える関数・演算子・コンストラクトがあります。
計算列とメジャーのどちらで書けばよいか迷ったら?
迷ったらメジャーで書きます。メジャーはモデルに値を保存しないため、更新時間とファイルサイズに影響しません。計算列にするのは、スライサーや凡例、軸に置きたい区分の列と、リレーションシップのキーに使う列だけです。文字列の連結のように同じ行の列だけで計算できるものは、Power Queryのカスタム列に移すと更新時の負荷が減ります。
CALCULATEのフィルター引数にメジャーを書くとエラーになるのはなぜですか?
ブール式のフィルター引数ではメジャーを参照できないという規則があるためです。利益が出た月だけの売上のように条件にメジャーを含める場合は、FILTER ( VALUES ( 'Date'[年月] ), [利益] > 0 )のようにテーブル式で渡します。列の値だけで書ける条件なら、FILTERを使わずブール式で書いたほうが速く動きます。
タイムインテリジェンス関数で前年の値が空白になるのはなぜですか?
多いのは3つの原因です。ビジュアルの軸に売上テーブル側の日付列を使っている、日付テーブルとのリレーションシップが無いか非アクティブになっている、日付テーブルに前年分の日付が無い、のいずれかです。軸には必ず'Date'テーブルの列を使い、CALENDARの期間には比較対象になる前年の分も含めてください。
DAXはCopilotに書かせてもよいですか?
下書きには使えますが、数字の検算は人が行う前提です。CopilotはDAXクエリビューで自然言語からクエリを生成し、既存のクエリの説明もできます。ただし期間の終点やフィルターの外し方を取り違えることがあるため、本記事のCALCULATEの書き方で読み解けることが前提です。必要な容量と使い方はPower BI CopilotでのDAX生成と検算の手順にまとめています。
関連記事
- Power BIとは?できること・料金・Excelやtableauとの違いから導入判断まで解説:DAXが動くPower BIの全体像と、Pro・PPU・容量の料金体系です。
- Power BI Copilotの使い方:必要な容量・設定手順とDAX生成・レポート作成の実装:CopilotでDAXを生成し、自分で書いたDAXで検算する手順です。
- Power BIのAPI連携:Web APIの取り込みとREST APIで更新・発行を自動化する手順:書いたDAXクエリをREST APIのExecute Queriesで実行する方法です。
- Power BI DesktopとServiceの違い:発行から更新・ゲートウェイ設定まで:Desktopで作ったメジャーをServiceへ発行し、更新するまでの流れです。
- セマンティックレイヤーとは?意味・仕組みから会話型AI時代の導入判断まで解説:メジャーの定義と用語をモデル全体でそろえる設計の考え方です。