Note
Microsoft Power Fx は、キャンバス アプリの数式言語の新しい名前です。 これらの記事は、Microsoftキャンバス アプリから言語を抽出し、他のMicrosoft Power Platform製品と統合し、オープンソースとして使用できるようになるため、進行中です。 言語の紹介のために Microsoft Power Fx の概要 から開始します。
Microsoft Power Fx テーブルでは、データをレコード、フィールド、およびMicrosoft Excel、SharePoint、SQL Serverなどのソースの列に整理します。 表形式データに効果的にアクセスし、整形し、操作する数式を記述するためのこれらの構造について説明します。
- レコードには、個人、場所、または物に関する 1 つ以上の情報カテゴリが含まれます。 たとえば、1 つのレコードに、単一の顧客の名前、電子メール アドレス、電話番号が含まれます。 他のツールでは、レコードを "行"や "項目" として参照します。
- テーブルは、同じ情報カテゴリを含む 1 つまたは複数のレコードを保持します。 たとえば、1 つのテーブルに 50 人の顧客の名前、電子メール アドレス、電話番号が含まれます。
Excel の式が引数として 1 つまたは複数のセルの参照を受け取るのと同様に、引数としてテーブルの名前を受け取るさまざまな式を作成できます。 Power Fx の一部の式では、指定された他の引数を反映するテーブルが返されます。 たとえば、次のような数式を作成できます:
- Patch 関数に対する複数の引数の 1 つとしてそのテーブルを指定することで、テーブル内のレコードを更新します
- AddColumns 関数、DropColumns 関数、または RenameColumns 関数の引数としてそのテーブルを指定することで、テーブル内の列を追加、削除、名前変更します。 これらの関数のいずれも、元のテーブルを変更することはありません。 代わりに、指定する他の引数に基づいて、関数は別のテーブルを返します。
テーブルの要素
レコード
各レコードには、人、場所、物についての少なくとも 1 つの情報カテゴリが含まれています。 前の例では、各製品 (チョコレート、 パン、 水) のレコードと、各カテゴリの情報 (価格、 手持数量、 注文数量) の列を示しています。
数式では、テーブルのコンテキストの外側で、中かっこを使用してレコード自体を参照できます。 たとえば、このレコード { 名前: "ストロベリー"、価格: 7.99 } はテーブルに関連付けられていません。 この例では、名前や価格などのフィールド名が二重引用符で囲まれていないことに注意してください。
フィールド
フィールドは、レコード内の個々の情報です。 この種のフィールドは特定のレコードの列の値として視覚化できます。
コントロールと同様に、レコードで . 演算子 を使用してレコードのフィールドを参照できます。 たとえば、First(Products).Name は、製品テーブル内の 1 つ目のレコードに対する名前フィールドを返します。
GroupBy 関数の例が示すように、フィールドに別のレコードやテーブルを含めることができます。 必要なだけ多くのレベルのレコードとテーブルを入れ子にできます。
列
列は、テーブル内の 1 つまたは複数のレコードの同じフィールドを参照します。 前の例では、各製品には価格フィールドがあり、その価格はすべての製品に対して同じ列にあります。 上の表には、上に水平方向に表示される 4 つの列があります。
- 名前
- 価格
- 手持ち在庫数量
- 注文数量
列の名前には、その列のフィールドが反映されます。
列内のすべての値は、同じデータ型です。 前の例では、"Quantity on Hand" 列には常に数値が含まれており、1 つのレコードに対して "12 単位" などの文字列を含めることはできません。 任意のフィールドの値も空白になる場合があります。
列は、他のツールでは「フィールド」と呼ばれることもあります。
テーブル
テーブルは 1 つ以上のレコードで構成され、各レコードには複数のフィールドであり、レコード間で名前が一貫しています。
データ ソースやコレクションに格納されている任意のテーブルには名前があり、テーブルを参照したり、引数として受け取る関数に渡すために使用します。 テーブルを関数や数式の結果にすることもできます。
次の例に示すように、Table 関数を使用して、一連のレコードを中かっこで表すことにより、数式をテーブルで表すことができます。
Table( { Value: "Strawberry" }, { Value: "Vanilla" } )
角かっこを使用して、単一の列テーブルを定義することもできます。 上記を書き込む同等の方法:
[ "Strawberry", "Vanilla" ]
テーブルの数式
Excel と Power Fx では、似た方法で数式を使用してテキストの数値と文字列を操作します:
- Excel では、セル A1 に 42 などの値を入力してから、別のセルに A1+2 などの数式を入力して、44 の値が表示されます。
- Power Apps では、Slider1 の Default プロパティを 42 に、ラベルの Text プロパティを Slider1.Value + 2 に設定して、44 の値を表示します。
どちらの場合も、引数の値 (たとえば、セル A1 の数値や Slider1 の値) を変更すると、計算された値が自動的に変更されます。
同様に、数式を使用して、テーブルやレコード内のデータにアクセスし、操作することができます。 カタログ テーブルの価格列内の最小値を表示する Min(Catalog, Price) など、テーブルの名前を一部の数式の引数として使用します。 RenameColumns(Catalog, "Price", "Cost") など、テーブル全体を戻り値として提供する他の数式もあります。これは、カタログ テーブルからのすべてのレコードを返しますが、価格列の名前をコストに変更します。
数値の場合と同様、テーブルやレコードを含む数式は、基になるテーブルやレコードが変更されると自動的に再計算されます。 カタログ テーブルにある製品のコストが以前の最小値よりも小さくなった場合、Min 数式の戻り値がそれに合わせて自動的に変更されます。
Table 関数とコントロール プロパティ
Lower 関数について検討しましょう。 変数 welcome がテキスト文字列 "Hello, World" を含む場合、数式 Lower( welcome ) は "hello, world" を返します。 この関数では、その変数の値は変更されません。 Lower は入力の処理と出力の生成のみを実行する、純粋な関数です。 それ以外の機能はなく、副作用もありません。 Excel のすべての関数と Power Fx のほとんどの関数は純粋な関数であり、ワークブックまたはアプリを自動的に再計算できます。
Power Fx は、同じ方法でテーブルを操作する一連の関数を提供します。 これらの関数は、テーブルを入力として受け取り、データのテーブル全体をフィルタ―処理、並べ替え、変換、削減、および要約します。 実際には、Lower 関数や、通常は単一の値を受け取る他の多くの関数も、単一列テーブルを入力として受け取ります。
多くの関数は、入力として単一列のテーブルを取得します。 テーブル全体に列が 1 つしかない場合は、名前で指定できます。 テーブルに複数の列がある場合は、Table.Column 構文を使用してそれらの列の 1 つを指定できます。 例えば、Products.Name は、製品テーブルからの名前値のみの単一列テーブルを返します。
AddColumns、RenameColumns、ShowColumns、または DropColumns 関数を使用して、必要に応じてテーブルを完全に再整形できます。 この場合も、これらの関数は出力のみを変更し、ソースは変更しません。
動作の数式
その他の関数はデータを変更するために特別に設計されており、副作用があります。 これらの関数は純粋ではないため、慎重に構築する必要があり、アプリでの値の自動再計算には使用できません。 これらの関数は、動作の数式内でのみ使用できます。
レコードのスコープ
一部の関数は、テーブルのすべてのレコード (一度に 1 つのレコード) で数式を評価することによって機能します。 数式の結果は、さまざまな方法で使用されます。
- AddColumns - 数式は、新しい列の値を提供します。
- Average、Max、Min、Sum、StdevP、VarP - 数式は集計する値を指定します。
- Filter、Lookup - 数式はレコードを出力に含めるかどうかを決定します。
- Concat - 数式は一緒に連結する文字列を決定します。
- Distinct - 数式は重複したレコードを識別するのに使用される 1 つの値を返します。
- ForAll - 数式は任意の値を返すことができ、副作用が生じる可能性もあります。
- Sort - 数式はレコードを並べ替えるための値を提供します。
- With - 数式は任意の値を返すことができ、副作用が生じる可能性もあります。
これらの数式内で、処理するレコードのフィールドを参照できます。 これらの関数ごとに、数式を評価するための "レコードのスコープ" が作成されます。この範囲にあるレコードのフィールドがは最上位の識別子として使用できます。 また、アプリ全体からのコントロール プロパティやその他の値を参照することもできます。
たとえば、グローバル変数に配置された製品のテーブルを取得します。
Set( Products,
Table(
{ Product: "Widget", 'Quantity Requested': 6, 'Quantity Available': 3 },
{ Product: "Gadget", 'Quantity Requested': 10, 'Quantity Available': 20 },
{ Product: "Gizmo", 'Quantity Requested': 4, 'Quantity Available': 11 },
{ Product: "Apparatus", 'Quantity Requested': 7, 'Quantity Available': 6 }
)
)
これらの製品の要求が利用可能な製品より多いかどうかを判断するには、次の手順を実行します。
Filter( Products, 'Quantity Requested' > 'Quantity Available' )
Filter への最初の引数は操作するレコードのテーブルで、2 つ目の引数は数式です。 Filter は、各レコードのフィールドが利用可能なこの数式を評価するためのレコード スコープを作成します。この場合は、製品、要求された数量、在庫数量です。 比較の結果によって、関数の結果に各レコードを含めるかどうかが決定されます:
この例に加えて、注文する各製品の量を計算できます。
AddColumns(
Filter( Products, 'Quantity Requested' > 'Quantity Available' ),
"Quantity To Order", 'Quantity Requested' - 'Quantity Available'
)
ここでは、計算列を結果に追加します。 AddColumns には、要求された内容と使用可能なものの差を計算するために使用する独自のレコード スコープがあります。
最後に、結果テーブルを目的の列のみに減らすことができます。
ShowColumns(
AddColumns(
Filter( Products, 'Quantity Requested' > 'Quantity Available' ),
"Quantity To Order", 'Quantity Requested' - 'Quantity Available'
),
"Product",
"Quantity To Order"
)
前の例では、一部の場所では二重引用符 (") を使用し、他の場所では単一引用符 (') を使用することに注意してください。 オブジェクトの名前にスペースが含まれている場合、フィールドやテーブルなどのオブジェクトの値を参照する場合は、単一引用符が必要です。 オブジェクトの値を参照せずに、代わりに、特に AddColumns の場合のように、オブジェクトがまだ存在しない場合は、二重引用符を使用します。
曖昧性の除去
レコード スコープで追加するフィールド名は、アプリ内の他の場所の同じ名前をオーバーライドします。 このオーバーライドが発生した場合でも、 @ のあいまいさを解消 する演算子を使用して、レコード スコープ外の値にアクセスできます。
- 入れ子になったレコード スコープから値にアクセスするには、次のパターンに従って、 @ 演算子を操作しているテーブルの名前と共に使用します。
Table[@FieldName] - データ ソース、コレクション、およびコンテキスト変数などのグローバル値にアクセスするには、[@オブジェクト名] のパターンを使用します (テーブルは指定しません)。
操作しているテーブルが Filter(Table, ... などの式である場合) )、あいまいさを解消する演算子は使用できません。 あいまいさを解消する演算子を使用しないことで、このテーブル式のフィールドにアクセスできるのは、最も内側のレコード スコープだけです。
たとえば、コレクション X があるとします。
このコレクションは 、ClearCollect( X, [1, 2] ) を使用して作成できます。
別のコレクション Y:
このコレクションは 、ClearCollect( Y, ["A", "B") を使用して作成できます。
さらに、Value という名前のコンテキスト変数を次の数式を使用して定義します: UpdateContext( {Value: "!"} )
これらを 1 つにまとめてみましょう。 このコンテキストでは、次の数式を使用します:
Ungroup(
ForAll( X,
ForAll( Y,
Y[@Value] & Text( X[@Value] ) & [@Value]
)
),
"Value"
)
次のテーブルが生成されます:
どうなっているのでしょうか? 最も外側の ForAll 関数は X のレコード スコープを定義するため、処理する各レコードの Value フィールドにアクセスできます。 それにアクセスするには、 Value という単語を使用するか 、X[@Value] を使用します。
最も内側の ForAll 関数は 、Y の別のレコード スコープを定義します。このテーブルには Value フィールドも定義されているため、ここで Value を使用すると 、Y のレコードのフィールドが参照され、 X のフィールドは参照されなくなります。 X の Value フィールドにアクセスするには、あいまいさを解消する演算子で長いバージョンを使用する必要があります。
Y は最も内側のレコード スコープであるため、このテーブルのフィールドにアクセスするにはあいまいさを解消する必要がないため、同じ結果でこの数式を使用できます。
Ungroup(
ForAll( X,
ForAll( Y,
Value & Text( X[@Value] ) & [@Value]
)
),
"Value"
)
すべての ForAll レコード スコープはグローバル スコープを上書きします。 定義した Value コンテキスト変数は、あいまいさを解消する演算子なしでは名前で使用できません。 この値にアクセスするには、[@Value] を使用します。
Ungroup は、入れ子になった ForAll 関数が入れ子になった結果テーブルとなるため、結果をフラット化します。
単一列テーブル
テーブルからの単一列を操作するには、この例のように ShowColumns 関数を使用します:
ShowColumns( Products, "Product" )
この数式は、この単一列テーブルを生成します:
より短い代替策に関しては、Table.Column を指定し、テーブルからの列の単一列のテーブルを抽出します。 たとえば、この数式は ShowColumns を使用した場合と全く同じ結果を生成します。
Products.Product
インライン レコード
名前付きフィールド値を含む中かっこを使用して、レコードを表します。 たとえば、次の数式を使用して、このトピックの冒頭に出てきたテーブル内の最初のレコードを表すことができます:
{ Name: "Chocolate", Price: 3.95, 'Quantity on Hand': 12, 'Quantity on Order': 10 }
次の例に示すように、数式を他の数式に埋め込むこともできます:
{ Name: First(Products).Name, Price: First(Products).Price * 1.095 }
次の例に示すように、中かっこを入れ子にすると、レコードを入れ子にすることができます。
{ 'Quantity': { 'OnHand': ThisItem.QuantOnHand, 'OnOrder': ThisItem.QuantOnOrder } }
空白やコロンなどの特殊文字が含まれる各列名を、単一引用符で囲みます。 列名内で単一引用符を使用するには、二重にします。
価格列の値にはドル記号などの通貨記号が含まれていない点に注意してください。 その書式設定は、値が表示されるときに適用されます。
インライン テーブル
Table 関数と一連のレコードを使用して、テーブルを作成します。 このトピックの冒頭で出てきたテーブルを、次の数式で表すことができます:
Table(
{ Name: "Chocolate", Price: 3.95, 'Quantity on Hand': 12, 'Quantity on Order': 10 },
{ Name: "Bread", Price: 4.95, 'Quantity on Hand': 34, 'Quantity on Order': 0 },
{ Name: "Water", Price: 4.95, 'Quantity on Hand': 10, 'Quantity on Order': 0 }
)
また、テーブルを入れ子にすることができます:
Table(
{ Name: "Chocolate",
'Quantity History': Table( { Quarter: "Q1", OnHand: 10, OnOrder: 10 },
{ Quarter: "Q2", OnHand: 18, OnOrder: 0 } )
}
)
インライン値テーブル
値を角かっこで指定することにより、単一列テーブルを作成できます。 結果のテーブルには、値という名前の単一列があります。
例えば、[ 1, 2, 3, 4 ] は Table( { Value: 1 }, { Value: 2 }, { Value: 3 }, { Value: 4 } ) に相当し、次のテーブルを返します: