以下の内容は、Ben Gribaudoのブログを参照して作成しました。
- Power Query M Primer (Part 4): Variables & Identifiers
- Power Query M Primer (Part 21): Identifier Scope & Sections
識別子(Regular Identifiers)
Power Queryでは、ステップごとに式の左側に変数が作成されます。これは、実行されている操作の値を保存し、次のステップに渡す役割があります。Power Queryでは、この変数を上書きすることはできず、1つのクエリの中で一意となるため、 識別子 と呼ばれます。
let
ソース = 1 + 2
in
ソース
識別子は、GUIで操作を行うと、操作の種類によって自動で作成されます。通常は、アプリケーションの言語(日本語)で付与されます。Power BI Desktopの「ファイル」⇒「オプションと設定」から「グローバル」の「地域の設定」を選択し、「常に英語」とすることで、英語にすることも出来ます。
オプションの「現在のファイル」にある「地域の設定」は、編集中のファイルについてのみ変更することができます。
引用符付き識別子(Quoted Identifiers)
英語で使用していると、GUIで作成される識別子に「#"」のようなプレフィックス、サフィックスが付いてくることがあります。名前の中にスペースが含まれる場合は #"Added Custom" のように、「"」で変数名が囲まれ、頭に「#」がつき、引用符付き識別子と呼ばれます。識別子に半角スペースが含まれる場合は、このように記述しなければエラーになります。
また、識別子に +-*/ のような文字が入る場合にも、 #"Price/2" のように識別子を囲う必要があります。
let
Source = Table.FromRecords({
[ID = 1, Item = "ハンバーガー", Price = 110.0]
}),
#"Take Two" = Table.AddColumn(Source, "Take Two", each [Price] * 2),
#"Price/2" = Table.AddColumn(#"Take Two", "Price/2", each [Price] / 2)
in
#"Price/2"
他のプログラム言語では、変数名にスペースを含めることはできません。Power Queryでは自由に記述でき、表記が見やすくなります。
引用符の必要ない識別子を引用符付識別子で記述しても、同じものとして扱われます。
let
Weight = 50
in
#"Weight"
ただし、日本語の設定で使っている場合は、GUIで自動付与される名前は全て全角文字が使用され、スペースが入ることはありません。
Power Queryの上級者は、詳細エディタでコードを書き込むため、グローバルの地域の設定を 「常に英語」 にし、GUIで自動付与された英語もスペースを削除して使用しています。その方が、直接記述するときにタイピングしやすく、判読しやすいためです。代表的なスペースの消し方は、以下のようになります。
#"Converted to Table" → ConvertedToTable
#"Converted to Table" → Converted_to_Table
一般識別子(Generalized Identifiers)
識別子は、変数だけでなく、レコードフィールドや列名も識別します。
列名を参照する場合、識別子が角括弧で囲まれて表記されます。上記の例2でも、式中に each [Price] * 2 のようにあります。このように角括弧で囲まれた識別子は、間にスペースが入っていても引用符付にする必要はありませんが、「+-*/」などの演算子が入っている場合は、引用符付にする必要があります。
let
Source = Table.FromRecords({
[ID = 1, Item = "ハンバーガー", Price = 110.0]
}),
#"Take Two" = Table.AddColumn(Source, "Take Two", each [Price] * 2),
#"Price/2" = Table.AddColumn(#"Take Two", "Price/2", each [Price] / 2),
#"Take Four" = Table.AddColumn(#"Price/2", "Take Four", each [Take Two] / 2),
#"Added Custom" = Table.AddColumn(#"Take Four", "Price/4", each [#"Price/2"] / 2)
in
#"Added Custom"
識別子参照
Power Queryでは、自分自身の識別子を参照することは出来ません。これを**排他的識別子参照(Exclusive Identifier Reference)**と言います。例えば、以下の例はエラーになります。
[
a = a * 10
]
ただし、再帰処理を行う場合は、@をつけて自分自身を参照することができます。これを、**包括的識別子参照(Inclusive Identifier References)**と言います。
let
SumConsecutive = (x) => if x <= 0 then 0 else x + @SumConsecutive(x - 1),
Result = SumConsecutive(4)
in
Result
下記のように、必要がない場合でも@をつけて記述できますが、意味はなく、混乱を招きます。必要な場合にのみ包括的参照を使用してください。
let
a = 2,
b = @a * 10
in
b
親子関係
1つの識別子に2度定義することはできませんが、親子関係になっている場合は可能です。
let
source = [
a = 10, // 親a
b = 20,
inner = [
a = a, // 子aは親aの値を参照し、10になります。
b = 2
]
]
in
source
上の例では、最初のa,b,cは親となっており、innerの中のa,b,cは子の関係になります。子aは親aを参照でき、a = a は自己参照ではなく、親の値を参照しています。同じ名前でも親子は違うものになります。ただし、親は子の値を参照することはできません。
クロスクエリ参照
クエリは、他のクエリの値を参照できます。次の2つのクエリがあります。
10
let
Result = Data
in
Result
例8は、Dataと名付けられた別のクエリの値を参照し、10を返します。しかし、以下のようにすると、
let
Data = 100,
Result = Data
in
Result // returns 100
ローカルのDataの値が優先されるため、帰ってくる値は100になります。
セクションアクセス式
敢えて、ローカルの値ではなく、Dataクエリの値を使いたい場合は、Section1 というキーワードを使用して参照することが可能です。
let
Data = 100,
Result = Section1!Data
in
Result //returns 10 (previously returned 100)
ローカルの100ではなく、Dataクエリの値 10 が返されます。
セクション
各クエリは、1つの親となるコンテナに含まれていることで、共通のスコープを持ちます。それをセクションといい、セクションドキュメント内(Section1)でクエリや関数、パラメータなどの識別子が定義されています。
また、そこに定義されている識別子は、グローバル環境(shared)に追加され、標準ライブラリと同様にアクセスできるようになります。