LWP | Power QueryのM言語を10の小さな実験で理解する
LWP TECHNICAL ARTICLE | 185
Power QueryのM言語を10の小さな実験で理解する
GUIの裏側にある「値・型・関数」の世界を30分で覗いてみる
Copyright © 2026 LWP 山中 一弘
本資料は、出典を明記いただければ、商用・非商用を問わず、ご自由に複製・改変・再配布していただけます。なお、著作権表示は改変せず、そのまま記載してご利用くださいますようお願いいたします。
記事要約
Power Queryは、Excelの画面から列削除や行抽出を行える便利なデータ変換機能です。しかし、GUIで行った操作の裏側では、M言語の式が作られ、ある値から次の値への変換が組み立てられています。
Mを最初から体系的に暗記する必要はありません。GUIが作った式を観察し、Table・Record・List、letとin、eachと_、関数、Durationといった要素を小さく試すだけでも、Power Queryの見え方は大きく変わります。
この記事では、一つの「中華料理」テーブルを共通データにして、M言語の特徴を10の実験で確認します。結論は、Mを「Excelセルを操作する手順」ではなく、値を受け取り、別の値を返す式の連鎖として読むことです。この見方を持つと、GUIで作ったクエリの読解、修正、再利用がしやすくなります。
本記事の対象とゴール
想定読者
Power QueryのGUI操作はできるが、数式バーや詳細エディターをほとんど見たことがない方
let、in、each、_、{}、[]の意味を実例でつかみたい方
M言語を本格的に学ぶ前に、どのような言語なのか短時間で体験したい方
本記事で得られること
GUI操作とMコードの関係を説明できます。
Table・Record・Listの違いと、値を取り出す記法を確認できます。
each、高階関数、クロージャー、再帰、式評価までを一続きの考え方として捉えられます。
はじめに 共通データを用意する
この記事のコードは、ExcelのPower Queryエディターで空のクエリを作り、[詳細エディター]へ貼り付けて試せます。最初に、共通の実験材料となる「中華料理」クエリを作ります。
クエリ名を 中華料理 とし、次のコードを貼り付けます。
let
Source =
#table(
type table [
料理名 = text,
分類 = text,
単価 = number,
数量 = number,
注文日 = date
],
{
{"麻婆豆腐", "一品料理", 900, 2, #date(2026, 8, 1)},
{"青椒肉絲", "一品料理", 1100, 1, #date(2026, 8, 5)},
{"小籠包", "点心", 600, 3, #date(2026, 8, 10)},
{"担々麺", "麺", 950, 2, #date(2026, 8, 15)},
{"海老炒飯", "飯", 1000, 1, #date(2026, 8, 20)},
{"回鍋肉", "一品料理", 850, 3, #date(2026, 8, 22)},
{"焼売", "点心", 550, 4, #date(2026, 8, 25)}
}
)
in
Source
#tableは、列の定義と行データからTable値を作ります。ここでは列ごとの型も明示しているため、以後の実験で文字列、数値、日付を区別できます。
各実験は、空のクエリへコードを貼り付けて単独で試せます。List、Record、関数など、共通テーブルだけでは説明しにくいものは、その場で小さな値を作ります。
第1章 GUIはMコードを生成している
1.1 列削除の裏側を見る
「中華料理」クエリで[分類]列を選び、GUIから列を削除します。数式バーには、次のような式が生成されます。
Table.RemoveColumns(Source, {"分類"})
GUIは単なる操作画面ではありません。選んだ操作をMの式へ翻訳するフロントエンドでもあります。
1.2 同じ処理を直接実行する
別の空のクエリで、次の式を試します。
Table.RemoveColumns(中華料理, {"分類"})
[分類]列を除いた新しいTableが返れば成功です。元の「中華料理」クエリそのものから列が消えるわけではありません。関数が元のTableを受け取り、列を除いた別のTableを返しています。
Mへの入り口は、白紙からすべて書くことではありません。
GUIで処理を作る。
数式バーや詳細エディターで生成されたMを見る。
必要な箇所だけ修正する。
この順序なら、普段の操作とコードを対応づけながら学べます。
第2章 適用したステップは値の連鎖である
2.1 前の値から次の値を作る
次のクエリは、列削除と行抽出を順に行います。
let
Source = 中華料理,
RemovedColumns = Table.RemoveColumns(Source, {"分類"}),
FilteredRows = Table.SelectRows(RemovedColumns, each [単価] >= 1000)
in
FilteredRows
処理の流れは、次のように読めます。
Sourceは「中華料理」と同じTableです。
RemovedColumnsは、Sourceから[分類]列を除いたTableです。
FilteredRowsは、RemovedColumnsから単価1,000円以上の行を選んだTableです。
inは、クエリ全体の結果としてFilteredRowsを返します。
適用したステップは「画面操作の履歴」に見えますが、Mの側から見ると、名前を付けた値どうしの依存関係です。
2.2 inを変えて途中結果を見る
最後だけ次のように変えます。
in
RemovedColumns
今度は、行を抽出する前のTableが返ります。letの中で途中の値を定義し、inで最終的に返す式を選ぶ。この構造が分かると、複数ステップのクエリを上から順に読みやすくなります。
第3章 Mはセルではなく値を扱う
Excelでは、A1、B5、Sheet1!C10のようにセルを中心に考えることが多くあります。Power QueryのMでは、Table、List、Recordなどの値を受け取り、新しい値を返す考え方が中心です。
次の式は、数量が2以上の行を選びます。
Table.SelectRows(
中華料理,
each [数量] >= 2
)
ここで行っているのは、特定のセルを上書きする処理ではありません。
入力は「中華料理」というTableです。
条件は「各行の数量が2以上」です。
出力は、条件を満たす行だけを持つ新しいTableです。
Excelのシート上では最終結果がセルへ読み込まれますが、クエリ内の思考単位はセル番地ではなく値です。
第4章 Table・Record・Listを見分ける
4.1 Listは順序を持つ値の並び
次の式は、4個のnumberを持つListです。
{900, 1100, 600, 950}
Listでは、項目を0から始まる位置で取り出せます。
{900, 1100, 600, 950}{0}
結果は900です。
4.2 Recordはフィールド名と値の組
次の式は、一つの料理を表すRecordです。
[
料理名 = "麻婆豆腐",
分類 = "一品料理",
単価 = 900,
数量 = 2
]
Recordでは、角括弧を使ってフィールドを取り出せます。
[
料理名 = "麻婆豆腐",
分類 = "一品料理",
単価 = 900,
数量 = 2
][単価]
結果は900です。
4.3 Tableは行と列を持つ
最初に作った「中華料理」はTableです。各行はRecordとして扱え、同じ列構造を持つRecordが並んでいると捉えると、Tableから値を取り出す記法が理解しやすくなります。
第5章 Tableから1行取るとRecordになる
5.1 0番目の行を取り出す
次の式を実行します。
中華料理{0}
結果はTableではなく、先頭行を表すRecordです。概念的には次の内容です。
[
料理名 = "麻婆豆腐",
分類 = "一品料理",
単価 = 900,
数量 = 2,
注文日 = #date(2026, 8, 1)
]
5.2 Recordからフィールドを取り出す
行を取り出した後に、料理名フィールドを選びます。
中華料理{0}[料理名]
結果は文字列の「麻婆豆腐」です。
この式は、左から順に次のように読めます。
中華料理はTableである。
{0}で先頭行を選ぶとRecordになる。
[料理名]でRecordのフィールドを選ぶとtextになる。
記号を暗記するだけでなく、「式を通過するたびに値の種類が変わる」と見るのがポイントです。
第6章 eachと_の正体は小さな関数である
6.1 金額列を追加する
単価と数量を掛けた[金額]列を追加します。
Table.AddColumn(
中華料理,
"金額",
each [単価] * [数量],
type number
)
麻婆豆腐の行なら、900×2で1,800になります。第4引数のtype numberは、追加列の型を明示しています。
6.2 eachは関数の省略記法
MicrosoftのM言語解説では、each ...は引数名を_とした関数の省略記法です。
each [単価] * [数量]
この式は、次の関数として読めます。
(_) => _[単価] * _[数量]
Table.AddColumnは各行をRecordとして関数へ渡します。_にはその時点の行が入り、_[単価]と_[数量]でフィールドを取り出します。
eachを「Power Query特有の不思議な予約語」と暗記するより、「引数を一つ受け取る短い関数」と考える方が応用できます。
第7章 関数そのものも値である
7.1 関数を名前へ入れる
次のコードでは、Text.Upperという関数そのものをfへ入れます。
let
f = Text.Upper
in
f("mapo tofu")
結果は次の文字列です。
MAPO TOFU
Text.Upperをその場で実行して結果を保存しているのではありません。関数値をfへ束縛し、その後で引数を渡して呼び出しています。
7.2 関数を渡せるから処理を部品化できる
Mでは、数値、文字列、List、Record、Tableだけでなく、関数も値として扱えます。関数を名前へ入れ、別の関数へ渡し、関数から返せます。
この性質が、Table.SelectRowsへ条件関数を渡す処理や、Table.AddColumnへ列の生成関数を渡す処理の土台です。
第8章 ループを書く代わりに関数を渡す
8.1 Listの全要素を10倍する
次の式は、Listの各要素へ同じ変換を適用します。
List.Transform(
{1, 2, 3},
each _ * 10
)
結果は次のListです。
{10, 20, 30}
処理順を制御するForループを書くのではなく、「各要素へ適用する変換」を関数として渡しています。
8.2 Tableの行抽出も同じ発想で読む
Table.SelectRows(
中華料理,
each [単価] >= 1000
)
Table.SelectRowsへ渡すのは、各行が残るかどうかを判定する関数です。
List.Transformは、各要素を別の値へ変換します。
Table.SelectRowsは、各行についてtrueまたはfalseを返す条件で行を選びます。
Table.AddColumnは、各行から新しい列の値を計算します。
関数名は違っても、「データと、データへ適用する関数を渡す」という形は共通しています。
第9章 日付の差はnumberではなくDurationになる
9.1 二つの注文日の差を求める
先頭行は2026年8月1日、5行目は2026年8月20日です。二つのdateを引きます。
中華料理{4}[注文日] - 中華料理{0}[注文日]
差は19日ですが、結果の型はnumberではなくdurationです。表示上は、次のような期間値になります。
#duration(19, 0, 0, 0)
9.2 日数というnumberへ変換する
日数だけが必要なら、Duration.Daysで日という構成部分を取り出せます。
Duration.Days(
中華料理{4}[注文日] - 中華料理{0}[注文日]
)
結果はnumberの19です。
dateやdatetimeは「いつか」を表し、durationは「どれだけ離れているか」を表します。Excelでは日付差が数値として見えますが、Mでは時点と時間の長さを別の型にするため、式の意味が明示されます。
時刻まで含む経過時間を小数の日数へ換算したい場合は、日部分だけを返すDuration.Daysではなく、Duration.TotalDaysを検討します。
第10章 Mは自分で関数を作り、関数を返し、式まで評価できる
ここでは詳細な文法を覚える必要はありません。Mがデータ整形専用の簡易記法ではなく、関数を組み立てられる言語であることを確認します。
10.1 自分で関数を作る
次のDoubleは、受け取った値を2倍する関数です。
let
Double = (x) => x * 2
in
Double(100)
結果は200です。
10.2 関数から関数を返す
次のAddは、最初の値を受け取ると、もう一つの値を加える関数を返します。
let
Add = (x) => (y) => x + y,
Add100 = Add(100)
in
Add100(20)
結果は120です。Add100は、最初に与えられた100を保持しています。関数が作られた環境の値を保持する仕組みがクロージャーです。
10.3 再帰関数を作る
次の関数は、5の階乗を求めます。
let
Factorial = (n as number) as number =>
if n <= 1 then
1
else
n * @Factorial(n - 1)
in
Factorial(5)
結果は120です。関数の定義内から自分自身を参照する箇所では、スコープ演算子@を付けています。
10.4 文字列に書かれたM式を評価する
Expression.Evaluateは、文字列として渡したM式を評価します。実務では、信頼できない文字列を無条件に渡しません。
Expression.Evaluate(
"100 + 20"
)
結果は120です。
まとめ Mを全部覚えなくても、Power Queryの見え方は変わる
この記事では、M言語の特徴を10の実験で確認しました。
GUI操作はMコードを生成しています。
適用したステップは、前の値から次の値を作る連鎖です。
Mはセル操作ではなく、Tableなどの値を変換します。
Table・Record・Listは、それぞれ異なる構造を持つ値です。
Tableから1行を選ぶとRecordになり、そこからフィールドを取り出せます。
eachは、引数名を_とした短い関数の省略記法です。
Mでは、関数そのものも値として扱えます。
データと処理関数を渡すことで、明示的なForループなしに変換できます。
日付の差は、時間の長さを表すdurationになります。
自作関数、クロージャー、再帰、式評価まで記述できます。
Mを学ぶときに重要なのは、関数名を大量に暗記することではありません。まず、式の入力と出力がどの種類の値なのかを追います。
Table
↓ 行を選ぶ
Record
↓ フィールドを選ぶ
text / number / date
↓ 関数へ渡す
別の値
GUIで処理を作り、生成されたMを覗き、分からない記号を一つずつ実験する。この繰り返しだけでも、Power Queryは「ボタンを押す道具」から「値の変換を設計する道具」へ変わって見えてきます。
参考資料
Microsoft Learn「Power Query M formula language introduction」
Microsoft Learn「M Language basic concepts」
Microsoft Learn「M Language Let」
Microsoft Learn「Understanding Power Query M functions」
Microsoft Learn「Table.AddColumn」
Microsoft Learn「Table.SelectRows」
Microsoft Learn「Duration support in Power Query M」
Microsoft Learn「Expression.Evaluate」
出典メモ
元原稿: C:\Users\hoehoe\Downloads\記事ネタmd\PowerQuery_M_10の小技_30分講義_記事元ネタ.md
元原稿の「共通の中華料理テーブルを使い、Mの特徴を10個の小実験で見る」という構成を主軸に、対象読者、確認方法、型の遷移、実務上の注意を補って公開記事へ再構成しました。
Mの値、let式、ListとRecordのアクセス、関数値、eachと_、再帰の@、Duration、Table.AddColumn、Table.SelectRows、Expression.Evaluateは、2026年8月21日にMicrosoft公式資料で確認しました。
公式資料: https://learn.microsoft.com/en-us/powerquery-m/m-spec-introduction
公式資料: https://learn.microsoft.com/en-us/powerquery-m/m-spec-basic-concepts
公式資料: https://learn.microsoft.com/en-us/powerquery-m/m-spec-let
公式資料: https://learn.microsoft.com/en-us/powerquery-m/understanding-power-query-m-functions
公式資料: https://learn.microsoft.com/en-us/powerquery-m/table-addcolumn
公式資料: https://learn.microsoft.com/en-us/powerquery-m/table-selectrows
公式資料: https://learn.microsoft.com/en-us/powerquery-m/durations
公式資料: https://learn.microsoft.com/en-us/powerquery-m/expression-evaluate
