目次
概要
Power Query では、M 言語で カスタム関数 を定義し、複数のクエリや列計算で繰り返し利用できます。本記事では、文字連結と数値スケーリングの関数を例に、作成から呼び出し、テーブル列への適用、例外処理までを丁寧にご説明いたします。変数名・引数名・数値は本記事用に変更しております。
基本:関数の作り方と呼び出し
1) 文字列を連結する関数(接頭辞は任意)
クエリ名: fxAddGreeting
(str as text, optional prefix as nullable text) as text =>
let
base = if prefix <> null then prefix else "Hello ",
result = base & str
in
result
- 使い方例
fxAddGreeting("森")
→Hello 森
fxAddGreeting("森", "こんにちは、")
→こんにちは、森
2) リストの各要素に係数を掛ける関数(既定は 10)
クエリ名: fxScaleList
(items as list, optional factor as nullable number) as list =>
let
k = if factor <> null then factor else 10,
scaled = List.Transform(items, each _ * k)
in
scaled
- 使い方例
fxScaleList({1, 2, 3})
→{10, 20, 30}
fxScaleList({2, 4, 6}, 0.5)
→{1, 2, 3}
実務での適用例
例A:テーブル列にあいさつ文を追加
let
Source = Excel.CurrentWorkbook(){[Name = "Employees"]}[Content],
Promoted = Table.PromoteHeaders(Source, [PromoteAllScalars = true]),
Typed = Table.TransformColumnTypes(Promoted, {{"Name", type text}}),
// 既に作成済みの fxAddGreeting を列計算で呼び出す
Added = Table.AddColumn(
Typed,
"Greeting",
each fxAddGreeting([Name]),
type text
)
in
Added
例B:数値列を一括スケーリング(係数はパラメータ)
let
Source = Excel.CurrentWorkbook(){[Name = "Sales"]}[Content],
Promoted = Table.PromoteHeaders(Source, [PromoteAllScalars = true]),
Typed = Table.TransformColumnTypes(Promoted, {{"Amount", type number}}),
// 係数 1.08(税率等)で倍率を掛ける
Scaled = Table.TransformColumns(
Typed,
{{"Amount", each List.First(fxScaleList({_}, 1.08)), type number}}
)
in
Scaled
応用
応用1:エラーに強いラッパー関数
数値変換で失敗しても null にフォールバックする関数です。
クエリ名: fxToNumberSafe
(x as any) as nullable number =>
let
v = try Number.From(x) otherwise null
in
v
- 列適用例 powerqueryコピーする編集する
SafeTyped = Table.TransformColumns( Promoted, {{"Amount", each fxToNumberSafe(_), type number}} )
応用2:関数を Folder 結合で再利用
フォルダ内の複数ブックへ同一処理を適用します。
let
Files = Folder.Files("C:\Data\Books"),
OnlyXlsx = Table.SelectRows(Files, each Text.Lower([Extension]) = ".xlsx"),
Picked = Table.SelectColumns(OnlyXlsx, {"Content", "Name"}),
WithTbl = Table.AddColumn(
Picked,
"Data",
each
let
wb = Excel.Workbook([Content], true, true),
sh = Table.SelectRows(wb, each [Kind] = "Sheet"){0}[Data],
hdr = Table.PromoteHeaders(sh, [PromoteAllScalars = true]),
out = Table.AddColumn(hdr, "Greeting", each fxAddGreeting([Name]))
in
out,
type table
),
Cols = Table.ColumnNames(WithTbl{0}[Data]),
Expand = Table.ExpandTableColumn(WithTbl, "Data", Cols, Cols)
in
Expand
応用3:既定値や検証を組み込む
(text as nullable text, optional maxLen as nullable number) as text =>
let
src = if text <> null then text else "",
m = if maxLen <> null then maxLen else 50,
cut = Text.Start(src, m),
clean = Text.Trim(cut)
in
clean
- 長すぎる説明文を切り詰め、前後の空白を除去する用途に適しています。
トラブルシューティング
- 関数が見つからない
クエリ名が関数名になります。呼び出し元からfxAddGreeting(...)
のように正しい名前で参照してください。 - 「式が期待される場所に識別子」などのエラー
let ... in ...
の カンマの位置、括弧の対応、識別子の綴り(例:Text.Start
など)を確認してください。 - 型不一致
引数や列の型をTable.TransformColumnTypes
で先に揃え、関数側の引数にもas text
やas number
の注釈を付けると安定します。
まとめ
例外処理(try … otherwise
)と型注釈を組み合わせることで、運用時のエラー耐性が向上します。
カスタム関数は 関数クエリ として作成し、他のクエリから呼び出して再利用します。
文字列処理や数値スケーリングのような小粒の関数を用意しておくと、列計算・フォルダ集約での再利用性が高まります。