実務で使えるPower Query小技・テクニック | each の意味を理解する

Excel VBA Power Query M Formula Language
スポンサーリンク
スポンサーリンク

each の正体を一言でいうと何か

Power Query(M言語)で頻出する each は、「無名関数(名前のない関数)の省略記法」です。 もう少し噛み砕くと、

「今処理している“1行分のデータ”を受け取って、その行に対して何か計算や判定をするための小さな関数を、その場で書くためのキーワード」

だと考えると理解しやすくなります。

Table.AddColumnTable.SelectRows など、 「テーブルの各行に対して何かする」系の関数でほぼ必ず登場しますので、 each の意味をきちんと理解しておくことは、M言語を実務で使ううえでの重要な基礎になります。

each は「行を受け取る無名関数」の省略形

無名関数の“素の形”を先に見てみる

まず、each を使わない場合の「無名関数」の形を見てみます。

(row as record) as any => row[金額] * 2
Power Query

これは、

  • 引数:row(1行分のレコード)
  • 戻り値:row[金額] * 2(その行の金額を2倍にした値)

という関数です。

これを Table.AddColumn に渡すと、各行の金額を2倍にした列を追加できます。

let
    SalesTable = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    AddedDoubleAmount =
        Table.AddColumn(
            SalesTable,
            "金額2倍",
            (row as record) as number => row[金額] * 2,
            type number
        )
in
    AddedDoubleAmount
Power Query

この「(row as record) => …」という形が、each の中身の正体です。

each を使うとどう短くなるか

同じ処理を each で書くと、こうなります。

let
    SalesTable = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    AddedDoubleAmount =
        Table.AddColumn(
            SalesTable,
            "金額2倍",
            each [金額] * 2,
            type number
        )
in
    AddedDoubleAmount
Power Query

ここでの each [金額] * 2 は、

「今処理している行を受け取って、その行の [金額] を2倍にする無名関数」

を省略して書いたものです。

つまり、

each [金額] * 2
Power Query

は、

(row as record) as any => row[金額] * 2
Power Query

の短縮形だと理解していただくと、each の意味が一気にクリアになります。

ステップバイステップで each の動きをイメージする

ステップ1:テーブルを1行ずつ処理するイメージを持つ

Table.AddColumnTable.SelectRows は、

  • テーブルを「1行ずつ」見ていく
  • 各行に対して「何をするか」を関数で指定する

という仕組みになっています。

その「各行に対して何をするか」を書く場所に、each がよく使われます。

例:金額の10%を「消費税額」として追加する

let
    SalesTable = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    AddedTaxAmount =
        Table.AddColumn(
            SalesTable,
            "消費税額",
            each [金額] * 0.1,
            type number
        )
in
    AddedTaxAmount
Power Query

ここでの each [金額] * 0.1 は、

「この行の [金額] を取り出して、0.1 を掛ける」

という処理を表しています。

テーブルの全行に対して、この処理が繰り返し適用されます。

ステップ2:フィルタ条件としての each

Table.SelectRows では、each が「行を残すかどうかを決める条件」として使われます。

let
    SalesTable = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    HighAmountThreshold = 1000,

    FilteredHighAmount =
        Table.SelectRows(
            SalesTable,
            each [金額] > HighAmountThreshold
        )
in
    FilteredHighAmount
Power Query

ここでの each [金額] > HighAmountThreshold は、

「この行の [金額] が閾値より大きいかどうかを判定する」

という処理です。

true を返した行だけが残り、false の行は除外されます。

「each は、行ごとの判定や計算を行うための小さな関数を書くためのキーワード」だとイメージしていただくと、使い方がぐっと分かりやすくなります。

ステップ3:each の裏側を“展開して”理解する

もう一度、each を使ったコードと、展開したコードを並べてみます。

// each を使った書き方
Table.AddColumn(
    SalesTable,
    "金額2倍",
    each [金額] * 2,
    type number
)
Power Query
// 展開した書き方
Table.AddColumn(
    SalesTable,
    "金額2倍",
    (row as record) as number => row[金額] * 2,
    type number
)
Power Query
  • each [金額] * 2 → 「行を受け取る無名関数」の省略形
  • row[金額] * 2 → 「行の中から金額列を取り出して2倍にする」

という対応関係になっています。

この「展開した形」を一度頭に入れておくと、

「each の中身は、行を引数に取る無名関数だ」

という理解が定着し、M言語の関数的な仕組みがぐっと見通しよくなります。

each の中で使えるもの・使えないもの

each の中で使える代表的なもの

each の中では、

  • 行の列:[金額], [顧客コード], [売上日] など
  • 外側で定義した変数:TaxRate, HighAmountThreshold など
  • 他の関数:Text.Upper, Number.Round, 自作関数など

を自由に使うことができます。

例:外側の変数と組み合わせる

let
    TaxRate = 0.1,
    SalesTable = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    AddedTaxAmount =
        Table.AddColumn(
            SalesTable,
            "消費税額",
            each [金額] * TaxRate,
            type number
        )
in
    AddedTaxAmount
Power Query

ここでは、

  • 各行の [金額]
  • 外側で定義した TaxRate

を組み合わせて計算しています。

each の中では「行の情報」と「外側の設定値」を同時に使える」というのが、実務で非常に強力なポイントです。

each の中での _ の意味

一部の関数では、each の中で _ という記号が使われます。

Table.TransformColumns(
    SalesTable,
    {
        {
            "顧客名",
            each Text.Upper(_),
            type text
        }
    }
)
Power Query

ここでの _ は、

「今処理している列の“そのセルの値”」

を表します。

  • Table.AddColumn の each:行全体(record)を暗黙的に受け取り、[列名] でアクセス
  • Table.TransformColumns の each:対象列のセル値を _ で受け取る

という違いがあります。

「行を扱うときは [列名]、セル値を扱うときは _という感覚を持っておくと、each の中身を迷わず書けるようになります。

each を使うときの重要な注意点

1. ロジックを詰め込みすぎない

each は便利なので、ついその中に複雑な処理を詰め込みがちです。 しかし、あまり複雑にすると、後から読む人(自分を含む)が理解しづらくなります。

悪い例:

each
    if [顧客コード] <> null and [顧客コード] <> "" and [金額] <> null and [金額] > 0 and Text.Length([顧客コード]) > 3 then
        [金額] * 1.1
    else
        null
Power Query

良い例:関数に切り出す

let
    CalcAdjustedAmount =
        (row as record) as nullable number =>
            let
                hasCustomer =
                    (row[顧客コード] <> null and row[顧客コード] <> "" and Text.Length(row[顧客コード]) > 3),
                hasPositiveAmount =
                    (row[金額] <> null and row[金額] > 0)
            in
                if hasCustomer and hasPositiveAmount then
                    row[金額] * 1.1
                else
                    null,

    SalesTable = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    AddedAdjustedAmount =
        Table.AddColumn(
            SalesTable,
            "調整後金額",
            each CalcAdjustedAmount(_),
            type nullable number
        )
in
    AddedAdjustedAmount
Power Query

each は「簡単な処理」に向いていて、複雑なロジックは名前付き関数に切り出した方が安全で読みやすいです。

2. null と型を意識する

each の中でも、null や型の扱いは非常に重要です。

each
    if [金額] = null then
        null
    else
        [金額] * 0.1
Power Query

このように、

  • null の場合の挙動
  • 計算対象が本当に数値かどうか

を意識して書くことで、 予期せぬエラーや不正な結果を防げます。

特に、外部データ(Excel・CSV・DB)を扱うときは、 「null が来る前提で each の中身を書く」くらいの意識がちょうどよいです。

3. セキュリティ・品質に関わる判定を each に丸投げしない

権限チェックや重要顧客判定など、セキュリティ・品質に関わるロジックを each の中に直接書くと、後からレビューしづらくなります。

悪い例:

Table.SelectRows(
    UserTable,
    each [Role] = "Admin" and [IsActive] = true
)
Power Query

良い例:関数に切り出す

let
    IsActiveAdmin =
        (row as record) as logical =>
            (row[Role] = "Admin" and row[IsActive] = true),

    FilteredAdmins =
        Table.SelectRows(
            UserTable,
            each IsActiveAdmin(_)
        )
in
    FilteredAdmins
Power Query

セキュリティに関わるロジックは、

  • 関数として名前を付ける
  • コメントで意図を明示する
  • レビューしやすい形にしておく

ことが大切です。

each はあくまで「適用の場」であり、重要なルールそのものは関数として別に定義しておく方が安全です。

実務で使える each テンプレート

テンプレ1:列追加での簡単な計算

let
    SalesTable = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    TaxRate = 0.1,

    AddedTaxAmount =
        Table.AddColumn(
            SalesTable,
            "消費税額",
            each [金額] * TaxRate,
            type number
        )
in
    AddedTaxAmount
Power Query

テンプレ2:フィルタ条件としての each

let
    SalesTable = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    HighAmountThreshold = 1000,

    FilteredHighAmount =
        Table.SelectRows(
            SalesTable,
            each [金額] <> null and [金額] > HighAmountThreshold
        )
in
    FilteredHighAmount
Power Query

テンプレ3:フラグ列の追加

let
    SalesTable = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    AddedValidFlag =
        Table.AddColumn(
            SalesTable,
            "有効行",
            each ([顧客コード] <> null and [顧客コード] <> "" and [金額] <> null and [金額] > 0),
            type logical
        )
in
    AddedValidFlag
Power Query

まとめ:each を理解することは「行ごとのロジック」を理解すること

M言語で each の意味を理解するというのは、 「テーブルの各行に対して、どんな小さな関数を適用しているのか」を理解することでもあります。

each は、

  • 行を受け取る無名関数の省略記法
  • 行の列([列名])と外側の変数を組み合わせて処理を書くための場所
  • 列追加・フィルタ・変換など、行単位のロジックの中心にあるキーワード

です。

ぜひ、

  • 「each は (row as record) => … の短縮形」
  • 「行を扱うときは [列名]、セル値を扱うときは _
  • 「簡単な処理は each、複雑な処理は関数に切り出す」

という感覚を身につけて、 実務の Power Query を、読みやすく・安全で・意図の伝わるコードに育てていっていただきたいです。

タイトルとURLをコピーしました