テクテク日記

テクテク=テクノロジー&一歩ずつ(テクテク)

DAX Query View (DQV)のいろいろ④

前回はDQVに関するTips(主にデバッグ関連)についてお伝えしました。DQVはDAXを扱うことになるため、DAXクエリを解釈する知識が必要です。そのため、初めはハードルが高く感じられるかもしれませんが、Power BIで洗練されたビジネスロジックを含むレポートを作成する際には不可欠なスキルです。

DQVは今後、Copilotの導入が期待されていますので、それまでに基礎知識をしっかり固めつつ、DAXの書き方に慣れていくことが重要です。

youtu.be

注: 動画で紹介されているDQVにおけるCopilot機能やビジュアルを右クリックしてデータポイントのDAXクエリを表示させる機能は、2023年12月時点ではまだ提供されていません。

今回はDEFINEステートメントとクエリスコープと言われるものについて解説をしていきたいと思います。なお、記事の中で「モデル」と表現することがありますが、特に言及がない限り、「セマンティックモデル」と同義になります。

DEFINEについて

DEFINEは、DAXクエリを記述する際に使用されるキーワードであり、様々なクエリを定義するためのものです。変数(VAR)、メジャー、列、クエリテーブルなどがDEFINEで定義できる要素です。DEFINEは、EVALUATE構文の一部であり、これを使用する際には必ずEVALUATEステートメントの前に配置する必要があります。

DEFINE ... EVALUATEという形でDAXクエリを記述していきますが、例えば以下のDEFINE MEASURE...EVALUATEの例を見てみます。


それぞれの数字(①~⑤)までのポイントは以下の通り。

  1. メジャーは、最初にDQVの「ローカルメジャー」として定義され、その後セマンティックモデルに適用されるまで、モデル内の数字に影響しない
  2. セマンティックモデルへの適用は、通常は「CodeLens」を使用して行います。ただし、すでにメジャーが存在する場合とそうでない場合では、表記が異なる
  3. 新たなメジャーを定義する際には、必ずTable[メジャー名]で記述する必要がある。背景には、メジャーは常にテーブルと関連しており、テーブルのメタデータとして使用されるため
  4. 既に存在するメジャーAと同じ名前を使用して、DEFINE(定義)をCodeLensで誤って行った場合、その定義はメジャーAを上書きする
  5. クエリエディタ内に同じ名前の要素が複数存在する場合、「実行」を試みるとエラーが発生する

「ローカルメジャー」という表現は、DQV(またはDAX Studio)でクエリを記述している際に使用される用語であり、「クエリスコープ*1」の概念と関連しています。具体的には、実際のセマンティックモデルに影響を及ぼす前段階であるDAXクエリをDQVで実行する際に使われます。つまり、ここでの操作は実際のセマンティックモデルに影響を与える処理を行う前の段階であることを想定しています。

DEFINEとEVALUATEの関係は、

DEFINEでローカルメジャー(CodeLensで実際のモデルへ適用可能)を定義し、EVALUATEで結果を返す

と覚えると分かりやすいでしょう。CodeLensを使用して実際のモデルに適用する場合、2023年12月時点ではメジャーのみに対応しており、今後は段階的に計算テーブルや計算列などにも対応していく予定です。

他にも重要な概念として、以下のものがあります。

  1. DEFINEで複数の要素を定義した後は、複数のEVALUATE文で利用が可能

    これは、1つのリクエストで複数のEVALUATEステートメントを実行できることを意味します。

  2. DEFINEとEVALUATE文の順序には注意が必要

    EVALUATEの後にDEFINEを挿入し、再度EVALUATEで評価しようとすると、エラーが発生しますので、順序に注意が必要です。

  3. DEFINE COLUMNやDEFINE TABLEも使用できますが、2023年12月末時点ではインテリセンス(自動補完機能)に対応しておらず、一部機能に制限があることから完全にサポートされていない状態。今後のPower BI Desktopの更新により、これらの機能が利用可能になる見通し。

    DEFINE COLUMNで定義された列(カラム)は、クエリスコープ内では計算列と同じような動作をし、1行ずつ評価されるため、Row Contextの特性を持ちます。DEFINE COLUMNではテーブル名を指定する必要がありますが、 EVALUATE + テーブル名で追加された列(計算列)を含むテーブルを評価することができます。

    一方、DEFINE TABLEで定義されたテーブルは、計算テーブルと同様の動作をし、EVALUATEステートメント内でCALCULATETABLEFILTERなどの関数を使用してさらに絞り込みを行うことが可能です。

DEFINEステートメントを使用することで、デバッグ時に一時的に使用するメジャーを作成し、それをテーブルビューとして可視化することが可能です。これは、CALCULATEと一緒に使うフィルター引数のように、通常見えない「仮想テーブル」をDEFINEステートメントで可視化することと同じく、次に説明するVARと必要に応じて使い分けることが望ましいでしょう。

なお、CodeLensを使用した実際のメジャー作成に関しては、2023年12月時点では一度に1つしか作成できない制限があります。今後のアップデートでこの制限が改善される見込みです。

クエリ変数(VAR)

DEFINEはキーワードにメジャー、テーブル、列の3つ以外に、変数(以下「VAR」)も指定することができます。VARはDAXにおいて以下のような特徴を持っています。

  • VARは「変数」ですが、評価が発生するのは1回のみであるため、実は「定数」扱い
  • VARはDAXコードの再利用性と可読性の向上に貢献
  • 複雑な計算をシンプルに表現
  • デバッグや調整の容易化
  • パフォーマンスの向上
  • VARキーワードは、大文字、小文字、混合のいずれでも問題なし(下図)
  • VARを記述する際、上図のように_を入れることが望ましい。理由は、VARがDAX関数と重複しないようにするためだけでなく、_を入れることで、そのVARを参照する際に_を先に入力すればVARだけが抽出されるため、使い勝手が向上するため

各特長に関する詳細は割愛しますが、Power BIでは

可能な限りVARを使うこと

がベストプラクティスの1つになります(ただし、VARを使ったことで混乱するケースも)。

通常、VARを使ったDAXコードの記述(DAXメジャー)はVAR...RETURNという形で終わります(下図)。

一方、VAR が EVALUATEステートメントの DEFINE セクションで使用されている場合は、EVALUATEにおいてどこでも使用できますが、RETURN キーワードは使用しません。

VARの内部はスカラー値であるため、最後のEVALUATE文では結果をテーブルで出力するためにテーブルコンストラクター { } を使用する必要があります。

もし、DEFINEで定義した変数以外にEVALUATEの後でさらに別の変数を定義する場合、その変数に対してRETURNを使用する必要があります。

もちろん、DEFINEを使用しないでEVALUATE + VARだけでも評価することができます。この場合、RETURNステートメントが必要になってきます。

凡そ混乱してきましたので、VARについてまとめると以下のように覚えてください。

  • EVALUATEの前にVARを使用する場合は、DEFINEが必要であり、EVALUATEの後に新しいVARを使用する場合はRETURNが必要

  • DEFINEを一切せず、EVALUATEの後でVARの変数を参照して計算させることは可能だが、RETURNが必要

  • どちらも最終的なアウトプットはテーブルにする必要がある

DEFINE VARとEVALUATE VARの大きな違いは、

前者は1つのリクエストで後続の全てのEVALUATEで使用できるが、後者はそのEVALUATEの中でしかVARを使用できない

ことにあります。DEFINEで定義したVARは後続の全てのEVALUATEで使用できることがポイントになります。

まとめ

今回は、DAXクエリを記述する際の対象要素(MEASURE、TABLE、COLUMN、VAR)について紹介しました。DAXの記述は初めての場合、慣れない部分があり、多くの人がDAXを難しいと感じることがあります。私自身も最初は非常に苦労しましたが、少しずつ慣れていくしかありません。お勧めとしては、今後新しいメジャーを記述する際に、DAXの関数バーではなく、DAXクエリ言語(DQV)を使って記述できるようになると、スキルの習得が一層早くなると考えられます。

*1:データベースやプログラミングのコンテキストにおいて、クエリ(問い合わせ)が実行される際の対象範囲や条件