実務で使えるPower Query小技・テクニック | 複数引数の関数を作る

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

複数引数の関数を作るとは何か

Power Query(M言語)で「複数引数の関数を作る」とは、1つの関数に対して、2つ以上の値やオブジェクトを入力として受け取り、それらを組み合わせて処理するロジックを定義することです。 単一引数の関数でも便利ですが、実務では「金額+税率+割引率」「テーブル+閾値」「文字列+フォーマット指定」など、複数の情報を同時に扱いたい場面が非常に多くなります。

複数引数の関数をきちんと設計できると、

  • 設定値を柔軟に変えられる
  • 同じ関数をさまざまな場面で再利用できる
  • セキュリティや品質チェックを汎用的に書ける といったメリットが得られます。

ここから、初心者向けにステップバイステップで「複数引数の関数」の考え方と書き方を解説していきます。

M言語における複数引数の基本構文

(引数1, 引数2, …) => 式 という形で書きます

複数引数の関数の基本形は次のようになります。

let
    CalcTaxIncluded =
        (price as number, taxRate as number) as number =>
            price * (1 + taxRate)
in
    CalcTaxIncluded
Power Query

ここでのポイントは、

  • (price as number, taxRate as number):引数が2つ並んでいる
  • as number:戻り値の型
  • price * (1 + taxRate):2つの引数を使った処理

という構造になっていることです。

引数はカンマ区切りで並べていきます。3つ以上でも同じです。

(price as number, taxRate as number, discountRate as number) as number =>
    ...
Power Query

ステップバイステップで「複数引数の関数」を作る

ステップ1:何を“別々の引数”として受け取りたいかを決める

複数引数に向いているのは、次のような組み合わせです。

  • 金額+税率+割引率
  • テーブル+閾値
  • 文字列+フォーマット指定
  • ロール(権限)+フラグ(有効/無効)

例:最終的な税込金額を計算する関数

let
    CalcFinalAmount =
        (price as number, taxRate as number, discountRate as number) as number =>
            let
                discount = price * discountRate,
                taxed = (price - discount) * (1 + taxRate)
            in
                taxed
in
    CalcFinalAmount
Power Query

ここでは、

  • price:元の金額
  • taxRate:税率
  • discountRate:割引率

という3つの引数を受け取る関数になっています。

ステップ2:呼び出し側で引数を順番通りに渡す

複数引数の関数を呼び出すときは、定義した順番通りに値を渡します。

let
    CalcFinalAmount =
        (price as number, taxRate as number, discountRate as number) as number =>
            let
                discount = price * discountRate,
                taxed = (price - discount) * (1 + taxRate)
            in
                taxed,

    TaxRate = 0.1,
    DiscountRate = 0.05,

    Final1 = CalcFinalAmount(1000, TaxRate, DiscountRate),
    Final2 = CalcFinalAmount(500, TaxRate, DiscountRate)
in
    [F1 = Final1, F2 = Final2]
Power Query

重要なのは、

  • 引数の「順番」が意味を持つ
  • 間違った順番で渡すと、意図しない計算になる

という点です。

例えば CalcFinalAmount(TaxRate, DiscountRate, 1000) のように順番を入れ替えてしまうと、 price に税率が入り、taxRate に割引率が入り…というおかしな状態になり、結果も壊れてしまいます。

複数引数の関数では「引数の順番」が非常に重要な設計要素になります。

ステップ3:テーブル処理の中で複数引数を渡す

実務では、テーブルの列と設定値を組み合わせて複数引数を渡すことが多いです。

let
    CalcFinalAmount =
        (price as number, taxRate as number, discountRate as number) as number =>
            let
                discount = price * discountRate,
                taxed = (price - discount) * (1 + taxRate)
            in
                taxed,

    TaxRate = 0.1,
    DiscountRate = 0.05,

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

    AddedFinalAmount =
        Table.AddColumn(
            SalesTable,
            "最終金額",
            each CalcFinalAmount([金額], TaxRate, DiscountRate),
            type number
        )
in
    AddedFinalAmount
Power Query

ここでは、

  • 各行の [金額]price 引数として渡し
  • 共通の TaxRateDiscountRate を他の引数として渡しています。

「行ごとの値+共通設定値」を複数引数として渡すのは、実務で非常に強力なパターンです。

型を付けた複数引数の設計

引数ごとに型を明示する

複数引数の関数では、引数ごとに型を付けることで、 関数の意図がよりはっきりします。

(price as number, taxRate as number, discountRate as number) as number =>
    ...
Power Query

型を付けるメリットは、

  • 間違った型の値が渡されたときに早期にエラーになる
  • 関数の役割が読みやすくなる
  • セキュリティ・品質の観点からも安全になる

という点です。

例:文字列クレンジング+フォーマット指定の関数

let
    FormatCustomerCode =
        (code as nullable text, toUpper as logical, trimSpaces as logical) as nullable text =>
            if code = null then
                null
            else
                let
                    trimmed =
                        if trimSpaces then
                            Text.Trim(code)
                        else
                            code,

                    formatted =
                        if toUpper then
                            Text.Upper(trimmed)
                        else
                            trimmed
                in
                    formatted
in
    FormatCustomerCode
Power Query

ここでは、

  • code:対象文字列
  • toUpper:大文字化するかどうか
  • trimSpaces:前後の空白を削除するかどうか

という3つの引数を受け取り、 それぞれの引数に応じて処理を変えています。

複数引数を使うことで、「同じ関数をさまざまな設定で使い回す」ことができるようになります。

null を含む複数引数の扱い

null を許容する引数は明示的に扱う

複数引数の中に null が入りうる場合、 どの引数が null を許容するのかを明示しておくことが重要です。

例:安全な割り算+閾値判定の関数

let
    SafeDivideWithThreshold =
        (x as nullable number, y as nullable number, threshold as number) as nullable logical =>
            if x = null or y = null or y = 0 then
                null
            else
                let
                    result = x / y
                in
                    result > threshold
in
    SafeDivideWithThreshold
Power Query

ここでは、

  • xy は null を許容する数値
  • threshold は必須の数値
  • 戻り値は「null または logical」

という設計になっています。

呼び出し例:

let
    R1 = SafeDivideWithThreshold(10, 2, 3),    // 10/2=5 → 5>3 → true
    R2 = SafeDivideWithThreshold(10, 0, 3),    // y=0 → null
    R3 = SafeDivideWithThreshold(null, 2, 3)   // x=null → null
in
    [R1 = R1, R2 = R2, R3 = R3]
Power Query

複数引数の関数では、「どの引数がnullを許容するか」「nullが来たときどう振る舞うか」を設計レベルで決めておくことが非常に重要です。

テーブルやレコードを含む複数引数

テーブル+閾値を引数にする関数

テーブルと設定値を組み合わせて引数にする例です。

let
    FilterHighAmountRows =
        (SalesTable as table, threshold as number) as table =>
            Table.SelectRows(
                SalesTable,
                each [金額] <> null and [金額] > threshold
            )
in
    FilterHighAmountRows
Power Query

呼び出し側:

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

    Threshold = 1000,

    HighAmountTable = FilterHighAmountRows(SalesTable, Threshold)
in
    HighAmountTable
Power Query

ここでは、

  • SalesTable:対象テーブル
  • threshold:金額の閾値

という2つの引数を受け取り、 「閾値を超える行だけを抽出したテーブル」を返しています。

テーブル+設定値を複数引数として関数化することで、フィルタロジックを汎用的に再利用できるようになります。

レコード+設定値を引数にする関数

1行分のレコードと設定値を組み合わせる例です。

let
    IsHighValueCustomer =
        (row as record, amountThreshold as number, rankThreshold as text) as logical =>
            let
                isHighAmount =
                    (row[金額] <> null and row[金額] > amountThreshold),
                isHighRank =
                    (row[ランク] <> null and row[ランク] <= rankThreshold)
            in
                isHighAmount and isHighRank
in
    IsHighValueCustomer
Power Query

テーブルに適用する例:

let
    IsHighValueCustomer =
        (row as record, amountThreshold as number, rankThreshold as text) as logical =>
            let
                isHighAmount =
                    (row[金額] <> null and row[金額] > amountThreshold),
                isHighRank =
                    (row[ランク] <> null and row[ランク] <= rankThreshold)
            in
                isHighAmount and isHighRank,

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

    AmountThreshold = 1000,
    RankThreshold = "B",

    AddedHighValueFlag =
        Table.AddColumn(
            SalesTable,
            "重要顧客",
            each IsHighValueCustomer(_, AmountThreshold, RankThreshold),
            type logical
        )
in
    AddedHighValueFlag
Power Query

ここでは、

  • 行全体(レコード)
  • 金額閾値
  • ランク閾値

という3つの引数を使って、「重要顧客かどうか」を判定しています。

複数引数を使うことで、「行の内容+外部設定」を組み合わせた高度な判定ロジックを関数として表現できるようになります。

セキュリティ・品質の観点からの複数引数

1. 権限判定関数に複数引数を使う

セキュリティに関わる関数では、ロールやフラグなどを複数引数として受け取ることがあります。

let
    CanExecuteProcess =
        (role as text, isActive as logical, isApproved as logical) as logical =>
            (role = "Admin" or role = "Manager")
                and isActive
                and isApproved
in
    CanExecuteProcess
Power Query

呼び出し側:

let
    Role = "Admin",
    IsActive = true,
    IsApproved = false,

    CanRun = CanExecuteProcess(Role, IsActive, IsApproved)
in
    CanRun
Power Query

このような関数を使う場合、

  • ロール名の管理方法
  • フラグの意味(誰がどう設定するか)
  • 誤って条件を緩くしてしまわないか

を意識しておく必要があります。

セキュリティに関わる複数引数の関数は、コメントやレビューを通じて意図を明確にし、変更時には慎重な運用が求められます。

2. 設定値を「引数にするか」「固定値にするか」の判断

複数引数の設計では、「どこまでを引数にするか」が重要な判断ポイントです。

  • 将来変更される可能性が高い値(税率・閾値・ロールなど)は引数にする
  • 絶対に変わらないルールは固定値でもよいが、コメントで意図を明示する

例:税率を固定値にした場合

let
    CalcTaxIncludedFixed =
        (price as number) as number =>
            price * 1.1   // 税率10%を固定
in
    CalcTaxIncludedFixed
Power Query

例:税率を引数にした場合

let
    CalcTaxIncludedFlexible =
        (price as number, taxRate as number) as number =>
            price * (1 + taxRate)
in
    CalcTaxIncludedFlexible
Power Query

実務では、「変更されうる値は引数にする」という方針が、保守性と安全性の両面で有利です。

実務で使える「複数引数の関数」テンプレート

テンプレ1:金額+税率+割引率

let
    CalcFinalAmount =
        (price as number, taxRate as number, discountRate as number) as number =>
            let
                discount = price * discountRate,
                taxed = (price - discount) * (1 + taxRate)
            in
                taxed
in
    CalcFinalAmount
Power Query

テンプレ2:テーブル+閾値

let
    FilterHighAmountRows =
        (SalesTable as table, threshold as number) as table =>
            Table.SelectRows(
                SalesTable,
                each [金額] <> null and [金額] > threshold
            )
in
    FilterHighAmountRows
Power Query

テンプレ3:レコード+設定値で重要顧客判定

let
    IsHighValueCustomer =
        (row as record, amountThreshold as number, rankThreshold as text) as logical =>
            let
                isHighAmount =
                    (row[金額] <> null and row[金額] > amountThreshold),
                isHighRank =
                    (row[ランク] <> null and row[ランク] <= rankThreshold)
            in
                isHighAmount and isHighRank
in
    IsHighValueCustomer
Power Query

まとめ:複数引数の関数を作ることは「ロジックを柔軟に設計すること」

M言語で「複数引数の関数を作る」というのは、 「1つの関数に対して複数の値やオブジェクトを入力として受け取り、それらを組み合わせて汎用的なロジックを設計すること」です。

これによって、

  • 同じ関数をさまざまな設定・条件で再利用できる
  • テーブルやレコードと設定値を組み合わせた高度な処理を書ける
  • 型やnullの扱いを引数ごとに設計でき、品質・セキュリティを高められる
  • 実務のロジックを「関数+複数引数」という形で整理しやすくなる

というメリットが得られます。

複数引数は、関数設計を一段階レベルアップさせる重要な要素ですので、 ぜひ「何を引数にするか」「順番と型をどう設計するか」「nullやセキュリティをどう扱うか」を意識しながら、 現場のロジックを複数引数の関数として育てていっていただきたいです。

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