
ForAll関数は使ってみるとわかるのですが、使い方が少し特殊ですが使い方がわかると結構便利な面もあります。とはいえ、色々調べてみてはいるのです、使い方をしっかりと理解しないと使い勝手が悪い関数でもあるので、実際に色々と検証してみて使い方を考えてみましょう。
PowerAppsに必須の知識PowerFX対応の学習本はこちら
PowerApps学習の本命・実際のアプリももらえる学習本
PowerApps学習方法一覧

ForAll関数とは
ForAll関数とはテーブルのそれぞれのレコードに対して計算などを行なってくれる関数になります。計算などを行う対象は全てのレコードになりますので、結果としてテーブルの中身(データ内容)を修正するときに使う関数となります。Patch関数は修正対象を指定することで特定のレコードを修正することができますが、 ForAll関数を使うことでテーブル内の全てのレコードを修正することができます。
そもそもForAll関数はテーブルを更新する関数ではなくテーブルのレコードを計算する関数であるということはForAll関数を知る上で重要な考えなのでしっかりと把握しましょう。
そして、ここが1番の問題点でもあると思いますが、ForAll関数は戻り値(関数を使った結果返ってくるデータ)を使うことも可能ですし、戻り値を使わないでも使用が可能となりますが、検証してみると戻り値はバグのようなものが見受けられるので使わない方が賢明でしょう。

こっちの記事で解説しているぞ。
入力内容
ForAll(テーブル名,各レコードに対する指示)
で入力します。
テーブル名と修正内容はどちらも必須項目になります。
入力内容詳細
テーブル名
テーブル名にはデータベースの名前を入力します。SharePointを使用している場合はリスト名を入力すれば大丈夫です。

レコードへの指示
修正内容にはもちろんレコードへの指示を入れるのですが、ここは注意が必要です。
テーブルの内容が1列の場合は列名と修正内容で修正することができますが、複数列の場合はPatch関数やThisRecord演算子を使って処理することになります。
ThisRecordとは名前の通りレコード(データテーブルの1行文のデータ)を対象としています。

戻り値
一旦マイクロソフトの公式内の記述を確認しましょう。
各数式の評価結果は、入力テーブルと同じ順序でテーブルに返されます。
数式の結果が単一の値の場合、結果として返されるテーブルは単一列のテーブルになります。 数式の結果がレコードの場合、結果として返されるテーブルには、結果のレコードと同じ列を含むレコードが格納されます。
数式の結果が 空 の値の場合、その入力レコードに対応するレコードが結果テーブルに存在しません。 この場合、結果テーブルのレコードはソース テーブルよりも少なくなります。
https://docs.microsoft.com/ja-jp/powerapps/maker/canvas-apps/functions/function-forall
正直に書くと、何言っているのかわかりませんでした。が色々と検証した結果としては
- 計算をするレコードに対して結果が一つであれば単一の列を返す
- 計算をするレコードに対して結果が複数であればテーブルで返す
- 計算結果が空である場合は戻り値として空を返すので元のデータよりレコード数が減る
というように考えてもらえれば大丈夫です。
例えば ClearCollect(Num,[1,2,3]) で単一の列である「num」テーブル(列名はValue)を作成しそのnumに ForAll(Num,If(Value=2,ThisRecord.Value+10)) で計算させます。ifの中身は2の場合は元のレコードに対して10を加算、その他の場合は何も返さないというようにしています。
これを変数で受けてみると次のようになります。

データはテーブルですが、2以外の数値に対しては空になっていますが、2に対しては10を加算した12になっています。よって元のテーブルより少ないレコード数が返ってきているということになります。
また、ClearCollect(table,{num:1,val:"a"},{num:2,val:"b"},{num:3,val:"c"})として複数列をForAll(table,If(num=2,ThisRecord))で計算した結果を変数で受けると次のようになります。

Patch関数と組み合わせる
ForAll関数はPatch関数と組み合わせることが多いです。Patch関数と組み合わせることで戻り値として指定しないでもデータテーブルを修正することができますが、考え方としては元のデータテーブルを修正するのではなく元のデータテーブルと同じ内容のデータテーブルを用意し修正する列以外の列の値が同じであればそのレコードを修正するということになります。
おそらく今これを読んでも理解できないとおもいますので、とりあえずのところはForAll関数は修正元のテーブルを編集できないので修正元のテーブルと同じ内容のものを用意してそれを修正すると考えてください。
組み合わせの基本
まずは次の画像を見てください。

ボタン1にはClearCollect(table,{num:1,val:"a"},{num:2,val:"b"},{num:3,val:"c"});ClearCollect(table2,table)という式が入っています。これで画像の中のtableというテーブルを作成し、同じ内容のtable2を作成しています。
ボタン2にはUpdateContext({変数:ForAll(table,Patch(table2,ThisRecord,{num:num+10}))})が入っています。これでnumに10を加算してtable2のテーブルを修正しています。画像はこのボタン2を押した結果になっています。
ということで、テーブル内のレコードを全部修正したい場合は
- ClearCollect (table,****) tableを作成
- ClearCollect(table2,table) tableと同じ内容のtable2を作成
- ForAll(table,Patch(table2,ThisRecord,{修正内容})) ForAllでtableを参照させてtable2を修正
ということで修正できます。
この時ForAllの結果を変数で受けみると次のような状態になります。

先に見たように修正対象のレコードが戻り値として設定されます。今回は全部のレコードが修正対象なので戻り値として設定されていることがわかります。
コピーしないといけない原因
ForAll関数はtableを参照していますが、ForAll関数が参照しているtableを修正することができません。そのため、修正はtable2に対して行います。
なぜ修正できないのかはマイクロソフトのみが知る技術的な仕様と割り切ってしまうのが良いかと思いますが、個人の感想としてはおそらく、ForAll関数は上から一件ずつ順番にレコードを修正していてその修正した結果は修正を反映させるデータテーブルに追加しているからだと思います。そのため、参照元の一番上のレコードを修正し参照元のテーブルに追加してしまうと永遠に処理し続ける無限ループに陥ってしまうためと考えられます。
先の例であえて書かなかったですが、ボタン2を連打してみるとtable2の内容がおかしくなります。

ここからわかるのはレコードがtable2に対して追加されているということです。そのため、参照元にレコードを追加してしまうと無限ループになってしまうというように考えた方が良さそうで、それをForAll関数では禁止しているのかもしれません。
修正が行われるレコードについて
修正対象のレコードは内容が一致しているかどうかで確認しています。次の画像を見てください。

今回はボタン1に
ClearCollect(table,{num:1,val:"a"},{num:2,val:"b"},{num:3,val:"c"});
ClearCollect(table2,{num:1,val:"aa"},{num:2,val:"bb"},{num:3,val:"c"})
を入れて実行しています。tableとtable2のvalをaとbだけ変えています。
これに対して先ほどのボタン2の内容を実行すると次のようになります。

valの内容が一致しているcはそのままnumが10加算されていますが、valが一致しないaとbに対しては10が加算された11と12がtable2に追加されています。
この時、変数でForAllの関数を受けてみると次のような形になります。

ここが少し理解できないポイントでもありますが、修正対象がしっかりと存在している場合はレコードを返してくれますが、修正対象が存在しない場合は修正した箇所のみを戻り値として返却しているようです。
この部分についてはそもそもマイクロソフトも想定していない使い方なのかもしれません。
使い方をまとめる
正直に書くと、このForAll関数はかなり挙動が不思議な部分があり、よくわからないというというのが印象です。PowerApps自体もまだまだ発展途中なアプリでもありますので、ForAll関数については理解するというよりも使い方を覚えるというような形が良いでしょう。
具体的には
- 列が単一の場合
- ForAll(テーブル名,列名と修正内容) でテーブルを修正する
- 戻り値で修正されたデータを受け取る
- 列が複数の場合
- ClearCollect(修正後のテーブル,修正元のテーブル) で修正元のテーブルを複製する
- ForAll(table,Patch(table2,ThisRecord,{修正内容})) でコピーしたテーブルを修正する
- 戻り値でデータを受け取るも可だが推奨しない
ということになります。
個人的にはテーブルを修正する場合には、UpdateIf関数の方が使いやすい気がします。
色々と気になる部分も多い関数ですが、マイクロソフトもそんなに特殊なことを想定して対応していないのかもしれません。