概要
Microsoft Power Query は、多くの機能を含む強力な "データの取得" エクスペリエンスを提供します。 Power Query の主な機能は、フィルター処理と結合、つまり、サポートされているデータ ソースの 1 つ以上の豊富なコレクションからデータを "マッシュアップ" することです。 このようなデータ マッシュアップは、Power Query 数式言語 (非公式には "M" と呼ばれます) を使用して表現されます。 Power Query は、Excel、Power BI、Analysis Services、Dataverse など、さまざまな Microsoft 製品に M ドキュメントを埋め込み、データの繰り返し可能なマッシュアップを可能にします。
このドキュメントでは、M の仕様について説明します。最初の直感と言語に関する知識を構築することを目的とした簡単な紹介の後、ドキュメントでは、いくつかの段階的な手順で言語を正確に説明します。
字句構造は、字句的に有効なテキストのセットを定義します。
値、式、環境と変数、識別子、および評価モデルは、言語の 基本的な概念を形成します。
値 の詳細な仕様は、プリミティブと構造化の両方で、言語のターゲット ドメインを定義します。
値 には、基本的な種類の値を特徴付け、構造化された値の形状に固有の追加のメタデータを保持する、型自体が特別な種類の値を持ちます。
M の 演算子 のセットは、形成できる式の種類を定義します。
別の種類の特別な値である関数は、M 用の豊富な標準ライブラリの基礎を提供し、新しい抽象化を追加できるようにします。
式の評価中に演算子または関数を適用すると、エラーが発生する可能性があります。 エラーは値ではありませんが、エラーを値にマップする エラーを処理 する方法があります。
Let 式を 使用すると、より小さな手順で複雑な式を構築するために使用される補助定義を導入できます。
式が 条件付き評価をサポートしている場合。
セクションは 簡単なモジュール性メカニズムを提供する。 (セクションはまだ Power Query で利用されていません)。
最後に、 統合文法 は、このドキュメントの他のすべてのセクションから文法フラグメントを 1 つの完全な定義に収集します。
コンピューター言語論者の場合:このドキュメントで指定されている数式言語は、ほとんどが純粋で、高次で、動的に型指定され、部分的に遅延する関数型言語です。
式と値
M の中心構造は 式です。 式を評価 (計算) し、1 つの 値を生成できます。
多くの値を式としてリテラルで書き込むことができますが、値は式ではありません。 たとえば、 1 式は値 1 に評価され、 1+1 式は値 2 に評価されます。 この区別は微妙ですが、重要です。 式は評価のためのレシピです。値は評価の結果です。
次の例は、M で使用できるさまざまな種類の値を示しています。慣例として、値はリテラル形式を使用して記述されます。この形式は、その値のみに評価される式に表示されます。 ( // は、行の末尾まで続くコメントの先頭を示します)。
プリミティブ値は、数値、論理、テキスト、null などの単一部分の値です。 null 値を使用して、データがないことを示すことができます。
123 // A number true // A logical "abc" // A text null // null valueリスト値は、順序付けられた値のシーケンスです。 M は無限リストをサポートしますが、リテラルとして書き込まれる場合、リストの長さは固定されます。 中かっこ
{および}は、リストの先頭と末尾を表します。{123, true, "A"} // list containing a number, a logical, and // a text {1, 2, 3} // list of three numbersレコードはフィールドのセットです。 フィールドは名前と値のペアで、名前はフィールドのレコード内で一意のテキスト値です。 レコード値のリテラル構文を使用すると、名前を引用符なしで記述できます。これは 、識別子とも呼ばれる形式です。 "
A"、"B"、および "C" という名前の 3 つのフィールドを含むレコードを次に示します。このフィールドには、1、2、および3の値があります。[ A = 1, B = 2, C = 3 ]テーブルは、列 (名前で識別される) と行に編成された値のセットです。 テーブルを作成するためのリテラル構文はありませんが、リストまたはレコードからテーブルを作成するために使用できる標準関数がいくつかあります。
例えば次が挙げられます。
#table( {"A", "B"}, { {1, 2}, {3, 4} } )これにより、次の図形のテーブルが作成されます。
関数は、引数を指定して呼び出されると新しい値を生成する値です。 関数は、関数の パラメーター をかっこで囲んで一覧表示し、その後に
=>行く記号の後に、関数を定義する式を記述します。 通常、その式はパラメーターを (名前で) 参照します。(x, y) => (x + y) / 2`
Evaluation
M 言語の評価モデルは、スプレッドシートでよく見られる評価モデルの後にモデル化されます。計算順序は、セル内の数式間の依存関係に基づいて決定できます。
Excel などのスプレッドシートで数式を記述した場合は、計算時に左側の数式が右側の値で認識される場合があります。
M では、式の一部は式の他の部分を名前で参照でき、評価プロセスによって参照される式の計算順序が自動的に決定されます。
レコードを使用して、前のスプレッドシートの例と同等の式を生成できます。 フィールドの値を初期化するときに、次の例に示すように、フィールドの名前を使用してレコード内の他のフィールドを参照できます。
[
A1 = A2 * 2,
A2 = A3 + 1,
A3 = 1
]
前の式は次の例と同じです (両方とも等しい値に評価されます)。
[
A1 = 4,
A2 = 2,
A3 = 1
]
レコードは、他のレコード内に格納することも、 入れ子にすることもできます。
ルックアップ演算子 ([]) を使用して、レコードのフィールドに名前でアクセスできます。 たとえば、次のレコードには、レコードを含む Sales という名前のフィールドと、Sales レコードのFirstHalfフィールドとSecondHalf フィールドにアクセスする Total という名前のフィールドがあります。
[
Sales = [ FirstHalf = 1000, SecondHalf = 1100 ],
Total = Sales[FirstHalf] + Sales[SecondHalf]
]
前の式は、評価時の次の例と同じです。
[
Sales = [ FirstHalf = 1000, SecondHalf = 1100 ],
Total = 2100
]
レコードはリスト内に含めることもできます。
位置指定インデックス演算子 ({}) を使用すると、リスト内の項目に数値インデックスでアクセスできます。 リスト内の値は、リストの先頭から 0 から始まるインデックスを使用して参照されます。 たとえば、インデックス 0 と 1 は、次の一覧の 1 番目と 2 番目の項目を参照するために使用されます。
[
Sales =
{
[
Year = 2007,
FirstHalf = 1000,
SecondHalf = 1100,
Total = FirstHalf + SecondHalf // 2100
],
[
Year = 2008,
FirstHalf = 1200,
SecondHalf = 1300,
Total = FirstHalf + SecondHalf // 2500
]
},
TotalSales = Sales{0}[Total] + Sales{1}[Total] // 4600
]
リストとレコードのメンバー式 (および let 式) は 、遅延評価を使用して評価されます。これは、必要に応じてのみ評価されることを意味します。 その他のすべての式は、 一括評価を使用して評価されます。つまり、評価プロセス中に検出されるとすぐに評価されます。 これについて考える良い方法は、リストまたはレコード式を評価すると、リストまたはレコードの値を返します。この値自体は、(ルックアップ演算子またはインデックス演算子によって) 要求されたときに、そのリスト アイテムまたはレコード フィールドを計算する必要がある方法を記憶します。
Functions
M では、 関数 は入力値のセットから 1 つの出力値へのマッピングです。 関数は、最初に必要な一連の入力値 (関数のパラメーター) に名前を付け、その後、その入力値 (関数の本体) を使用して関数の結果を計算する式を、ゴート (=>) 記号の後に指定することによって書き込まれます。 例えば次が挙げられます。
(x) => x + 1 // function that adds one to a value
(x, y) => x + y // function that adds two values
関数は、数値やテキスト値と同様の値です。 次の例は、Add フィールドの値である関数を示しています。これは、他のいくつかのフィールドから 呼び出されるか、実行されます。 関数が呼び出されると、関数本体式内で必要な入力値のセットに論理的に置き換える値のセットが指定されます。
[
Add = (x, y) => x + y,
OnePlusOne = Add(1, 1), // 2
OnePlusTwo = Add(1, 2) // 3
]
図書館
M には、 標準ライブラリと呼ばれる式から使用できる共通の定義セット、または略して 単にライブラリ が含まれています。 これらの定義は、名前付き値のセットで構成されます。 ライブラリによって提供される値の名前は、式によって明示的に定義されていない式内で使用できます。 例えば次が挙げられます。
Number.E // Euler's number e (2.7182...)
Text.PositionOf("Hello", "ll") // 2
オペレーター
M には、式で使用できる演算子のセットが含まれています。
演算子 はオペランドに適用され 、 シンボリック式が形成されます。 たとえば、式 1 + 2 では、数値 1 と 2 はオペランドであり、演算子は加算演算子 (+) です。
演算子の意味は、オペランドの値の種類によって異なる場合があります。 たとえば、プラス演算子は、数値以外の種類の値と共に使用できます。
1 + 2 // numeric addition: 3
#time(12,23,0) + #duration(0,0,2,0)
// time arithmetic: #time(12,25,0)
オペランドに依存する意味を持つ演算子のもう 1 つの例は、組み合わせ演算子 (&) です。
"A" & "BC" // text concatenation: "ABC"
{1} & {2, 3} // list concatenation: {1, 2, 3}
[ a = 1 ] & [ b = 2 ] // record merge: [ a = 1, b = 2 ]
一部の演算子では、値の組み合わせがすべてサポートされていない場合があることに注意してください。 例えば次が挙げられます。
1 + "2" // error: adding number and text isn't supported
評価時に未定義の演算子条件が発生し、 エラーと評価される式。
メタデータ
メタデータ は、値に関連付けられている値に関する情報です。 メタデータは、 メタデータ レコードと呼ばれるレコード値として表されます。 メタデータ レコードのフィールドを使用して、値のメタデータを格納できます。
すべての値にはメタデータ レコードがあります。 メタデータ レコードの値が指定されていない場合、メタデータ レコードは空です (フィールドがありません)。
メタデータ レコードは、目立たない方法で追加情報をあらゆる種類の値に関連付ける方法を提供します。 メタデータ レコードを値に関連付けることは、値やその動作を変更しません。
yメタデータ レコード値は、構文x meta yを使用して、既存の値x関連付けられます。 たとえば、次のコードでは、メタデータ レコードを Rating フィールドに関連付け、 Tags フィールドをテキスト値 "Mozart"に関連付けます。
"Mozart" meta [ Rating = 5, Tags = {"Classical"} ]
空でないメタデータ レコードを既に保持している値の場合、メタを適用した結果は、既存のメタデータ レコードと新しいメタデータ レコードのレコードマージを計算した結果です。 たとえば、次の 2 つの式は、互いに同じで、前の式と同等です。
("Mozart" meta [ Rating = 5 ]) meta [ Tags = {"Classical"} ]
"Mozart" meta ([ Rating = 5 ] & [ Tags = {"Classical"} ])
Value.Metadata関数を使用して、特定の値のメタデータ レコードにアクセスできます。 次の例では、 ComposerRating フィールドの式は、 Composer フィールドの値のメタデータ レコードにアクセスし、メタデータ レコードの Rating フィールドにアクセスします。
[
Composer = "Mozart" meta [ Rating = 5, Tags = {"Classical"} ],
ComposerRating = Value.Metadata(Composer)[Rating] // 5
]
Let 式
これまでに示した多くの例では、式の結果に式のすべてのリテラル値が含まれています。
let式を使用すると、一連の値を計算し、名前を割り当ててから、inの前にある後続の式で使用できます。 たとえば、売上データの例では、次の操作を行うことができます。
let
Sales2007 =
[
Year = 2007,
FirstHalf = 1000,
SecondHalf = 1100,
Total = FirstHalf + SecondHalf // 2100
],
Sales2008 =
[
Year = 2008,
FirstHalf = 1200,
SecondHalf = 1300,
Total = FirstHalf + SecondHalf // 2500
],
TotalSales = Sales2007[Total] + Sales2008[Total]
in
TotalSales // 4600
上記の式の結果は、Sales2007およびSales2008名にバインドされた値から計算される数値 (4600) です。
If 式
if式は、論理条件に基づいて 2 つの式の間で選択します。 例えば次が挙げられます。
if 2 > 1 then
2 + 2
else
1 + 1
論理式 (2 > 1) が true の場合は最初の式 (2 + 2) が選択され、false の場合は 2 番目の式 (1 + 1) が選択されます。 選択した式 (この場合は 2 + 2) が評価され、 if 式 (4) の結果になります。
Errors
エラーは、式を評価するプロセスで値を生成できなかったことを示します。
エラーは、エラー状態が発生した演算子と関数、またはエラー式を使用して発生します。 エラーは、 try 式を使用して処理されます。 エラーが発生すると、エラーが発生した理由を示すために使用できる値が指定されます。
let Sales =
[
Revenue = 2000,
Units = 1000,
UnitPrice = if Units = 0 then error "No Units"
else Revenue / Units
],
UnitPrice = try Number.ToText(Sales[UnitPrice]),
Result = "Unit Price: " &
(if UnitPrice[HasError] then UnitPrice[Error][Message]
else UnitPrice[Value])
in
Result
上記の例では、 Sales[UnitPrice] フィールドにアクセスし、結果を生成する値を書式設定します。
"Unit Price: 2"
Units フィールドが 0 の場合、UnitPrice フィールドでエラーが発生し、tryによって処理されます。 結果の値は次のようになります。
"Unit Price: No Units"
try式は、適切な値とエラーを、try式がエラーを処理したかどうかを示すレコード値と、エラーの処理時に抽出された適切な値またはエラー レコードに変換します。 たとえば、エラーを発生させ、すぐに処理する次の式を考えてみましょう。
try error "negative unit count"
この式は、次の入れ子になったレコード値に評価され、前の単価の例での [HasError]、 [Error]、および [Message] フィールドの参照について説明します。
[
HasError = true,
Error =
[
Reason = "Expression.Error",
Message = "negative unit count",
Detail = null
]
]
一般的なケースは、エラーを既定値に置き換える場合です。
try式は、省略可能なotherwise句と共に使用して、コンパクトな形式で実現できます。
try error "negative unit count" otherwise 42
// 42