Tables
注意
Microsoft Power Fx は、キャンバス アプリの数式言語の新しい名前です。 これらの記事は、キャンバス アプリから言語を抽出し、その他の 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 つの列があります。
- 名前
- 価格
- 在庫数
- 注文数量
列の名前には、その列のフィールドが反映されます。
列内のすべての値は、同じデータ型です。 上の例で、 「手持ち在庫数量」 列には常に数値が含まれ、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 関数を使用して、必要に応じてテーブルを完全に再整形できます。 この場合も、これらの関数は出力のみを変更し、ソースは変更しません。
動作の数式
その他の関数はデータを変更するために特別に設計されており、副作用があります。 これらの関数は純粋ではないため、慎重に構築する必要があり、アプリでの値の自動再計算には使用できません。 これらの関数は、動作の数式内でのみ使用できます。
レコードのスコープ
一部の関数は、テーブルのすべてのレコード間で個別に数式を評価することにより動作します。 数式の結果は、さまざまな方法で使用されます:
- AddColumns - 数式は追加されたフィールドの値を提供します。
- 平均、 最大、 最小、 合計、 標準偏差P、 分散P - 数式は集計する値を提供します。
- フィルター、 ルックアップ - 数式によって、レコードを出力に含めるかどうかが決まります。
- Concat - 数式によって連結する文字列が決定されます。
- Distinct - 数式は重複レコードを識別するために使用される値を返します。
- 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 つ目の引数は数式です。 フィルター は、この数式を評価するためのレコード スコープを作成します。このスコープでは、各レコードのフィールド (この場合は 製品、 要求数量、および 使用可能な数量) が使用可能です。 比較の結果によって、関数の結果に各レコードを含めるかどうかが決定されます:
この例に追加して、各製品の受注量を計算できます:
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 の場合のように、オブジェクトがまだ存在しない状況でそれについて話している場合に使用されます。
曖昧性の除去
レコード スコープによって追加されたフィールド名は、アプリの別の場所にある同じ名前を上書きします。 これが発生した場合でも、@ 曖昧性除去演算子を使用して、レコード スコープの外部からの値にアクセスできます:
- 入れ子になったレコード スコープの値にアクセスするには、次のパターンを使用した操作対象のテーブルの名前の @ 演算子を使います。
テーブル[@フィールド名] - データ ソース、コレクション、およびコンテキスト変数などのグローバル値にアクセスするには、[@オブジェクト名] のパターンを使用します (テーブルは指定しません)。
操作対象のテーブルが、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 のレコード スコープが定義されます。これにより、処理の際に各レコードの値フィールドにアクセスできます。 単に値という単語か X[@Value] を使用してアクセスできます。
最も内側の ForAll 関数は Y の別のレコード スコープを定義します。このテーブルには定義された値フィールドもあるため、ここで値を使用すると Y のレコードのフィールドが参照され、X のフィールドは参照されなくなります。ここで、X の値フィールドにアクセスするには、曖昧性除去演算子を使用した長いバージョンを使用する必要があります。
Y は最も内側のレコード スコープのため、このテーブルのフィールドにアクセスする際に曖昧性除去は必要ありません。同じ結果になるこの数式を使用できます:
Ungroup(
ForAll( X,
ForAll( Y,
Value & Text( X[@Value] ) & [@Value]
)
),
"Value"
)
すべての ForAll レコード スコープはグローバル スコープを上書きします。 定義した Value コンテキスト変数は、曖昧性除去演算子がなければ名前で参照することができません。 この値にアクセスするには、[@Value] を使用します。
ネストされた ForAll 関数の結果がネストされた結果テーブルとなるため、Ungroup は結果をフラット化します。
単一列テーブル
テーブルからの単一列を操作するには、この例のように 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 } )
に相当し、次のテーブルを返します: