LWP | Power Queryで複数データを一つにまとめる設計パターン
LWP TECHNICAL ARTICLE | 163
Power Queryで複数データを
一つにまとめる
設計パターン
フォルダー結合からmap・flatMap・fold・unfold・スキーマ設計までを一つの判断軸で理解する
Copyright © 2026 LWP 山中 一弘
本資料は、出典を明記いただければ、商用・非商用を問わず、ご自由に複製・改変・再配布していただけます。なお、著作権表示は改変せず、そのまま記載してご利用くださいますようお願いいたします。
記事要約
Power Queryでフォルダー内の複数CSVを縦に結合する方法は一つではありません。フォルダーテーブルへ子テーブルを追加して展開する方法、各CSVを同格のテーブルへ変換して最後にTable.Combineする方法、Recordへ分解して再構築する方法、状態をList.Accumulateで引き継ぐ方法などがあります。
重要なのは、関数の種類を増やすことではありません。「何を処理の主語にするか」「どのデータ型を中間表現にするか」「何を引き継ぐか」「何を一つとみなすか」「最後にどの演算を行うか」を分けて考えることです。
通常の業務CSVでは、ファイル単位の読込・正規化関数を作り、由来情報を付け、同じ完成スキーマへそろえたテーブルのリストを最後に一度だけTable.Combineする形が第一候補になります。一方、前回状態が次へ影響するならList.Accumulate、次の入力を状態から作るならList.Generate、階層を残すならTable.Group、別の実体情報を付けるならJoinを選びます。
本記事の対象とゴール
想定読者
Power QueryでCSVやExcelファイルを結合した経験がある方
Table.AddColumnと展開以外の設計も理解したい方
List、Record、関数を実務の部品として使いたい方
列増減、形式差、エラー、由来情報を含めて壊れにくく設計したい方
本記事で得られること
Expand、Combine、Join、Groupの役割をデータの形から区別できます。
map、flatMap、fold、unfoldをM言語の具体的な処理へ対応づけられます。
単純結合、状態遷移、入力生成、階層保持、異形式統合を使い分けられます。
完成スキーマ、由来情報、エラー方針を先に決めた実務的な統合処理を設計できます。
目次
はじめに 「一つにまとめる」を分解する
第1章 すべてのパターンに共通する読込関数
第2章 通常のフォルダー結合を三つの形で比べる
第3章 中間表現を変える
第4章 状態と入力を生成する
第5章 階層・スキーマ・キー・規則で統合する
第6章 11の設計パターンを選び分ける
第7章 実務で壊れにくくする
第8章 通常の業務CSVに対する推奨構成
まとめ 関数ではなく主語とデータの形を選ぶ
はじめに 「一つにまとめる」を分解する
0.1 同じ結果でも設計の主語は異なる
次の3ファイルを1つの明細テーブルへまとめる処理を考えます。
売上_東京.csv
売上_大阪.csv
売上_名古屋.csv
↓
すべての売上明細を1つのテーブルへまとめる
この処理は、少なくとも次のように書けます。
フォルダー表へ解析結果のTable列を追加し、その列を展開する
各CSVをTableへ変換し、Tableのリストを最後に結合する
各行をRecordへ変換し、Recordのリストから完成表を作る
入力を順に処理し、状態Recordへ結果とエラーを蓄積する
どれも「複数CSVをまとめる」処理ですが、主語と中間表現が違います。
0.2 共通の変換モデル
複数ソースの統合は、次の段階へ分解できます。
入力を列挙する
↓
入力ごとに解釈する
↓
共通の形へ正規化する
↓
入力元の情報を付ける
↓
目的に合う演算で一つにする
↓
エラーや処理履歴を返す
短く表すと、次の構造です。
Result = Assemble(Contextualize(Normalize(Parse(Source))))
設計時には、次の5項目を別々に決めます。
入力単位: ファイル、行、APIページ、会社、年度など
中間表現: Binary、Text、Table、List、Record、状態Recordなど
引き継ぐ文脈: ファイル名、パス、更新日時、連番、前回残高、エラーなど
完成単位: 全明細、会社別明細、同一顧客、データとエラーを含むRecordなど
最終演算: Expand、Combine、Join、Group、Accumulate、Generateなど
第1章 すべてのパターンに共通する読込関数
1.1 CSV解析を分離する
比較する処理からCSV解析の詳細を切り離すため、Binaryを受け取ってTableを返す関数fnReadCsvを用意します。
let
fnReadCsv =
(Binary as binary) as table =>
let
Parsed =
Csv.Document(
Binary,
[
Delimiter = ",",
Encoding = 65001,
QuoteStyle = QuoteStyle.Csv
]
),
Promoted =
Table.PromoteHeaders(
Parsed,
[PromoteAllScalars = true]
)
in
Promoted
in
fnReadCsv
この関数の責任は、次の3点だけです。
BinaryをCSVとして解釈する。
先頭行をヘッダーへ昇格する。
Tableを返す。
フォルダーの列挙、ファイル名の付与、列名の正規化、全体の結合は別の処理へ分けます。
1.2 ヘッダーはファイルごとに処理する
複数CSVのBinaryや行を先に連結し、最後に一度だけヘッダーを昇格すると、2ファイル目以降のヘッダーがデータ行として残る可能性があります。
CSV Aのヘッダー
CSV Aのデータ
CSV Bのヘッダー ← データとして残る
CSV Bのデータ
原則として、CSVごとに解析とヘッダー昇格を完了し、その後で結果Tableを統合します。
第2章 通常のフォルダー結合を三つの形で比べる
2.1 親子展開型:外側の文脈を保って平らにする
Folder.Filesの結果を親テーブルとし、各ファイル行へ解析後の子テーブルを追加します。
let
Files =
Folder.Files(FolderPath),
CsvFiles =
Table.SelectRows(
Files,
each
Text.Lower([Extension]) = ".csv"
and [Attributes]?[Hidden]? <> true
),
WithData =
Table.AddColumn(
CsvFiles,
"Data",
each fnReadCsv([Content]),
type table
),
ExpandColumns =
{"Date", "CustomerCode", "Amount"},
Result =
Table.ExpandTableColumn(
WithData,
"Data",
ExpandColumns,
ExpandColumns
)
in
Result
この設計の主役は、外側のフォルダー表です。子テーブルを展開すると、Name、Folder Path、更新日時などの親の列が、子テーブルの各行へ引き継がれます。
ファイルAの文脈 + 明細1
ファイルAの文脈 + 明細2
ファイルBの文脈 + 明細1
これは概念的にはflatMapに近い処理です。親の1行を子の複数行へ変換し、親の文脈を保ったまま平らな表にします。
この形は、ファイル属性を残したい場合、展開前にファイル単位の結果を確認したい場合、列構成が固定されている場合に向きます。
2.2 部品合成型:同格のTableを最後に結合する
各CSVを独立したTable部品へ変換し、Tableのリストを最後に一度だけTable.Combineします。
let
Files =
Folder.Files(FolderPath),
CsvFiles =
Table.SelectRows(
Files,
each
Text.Lower([Extension]) = ".csv"
and [Attributes]?[Hidden]? <> true
),
Sources =
Table.ToRecords(CsvFiles),
Tables =
List.Transform(
Sources,
(Source) =>
let
Parsed =
fnReadCsv(Source[Content]),
WithSource =
Table.AddColumn(
Parsed,
"Source.Name",
each Source[Name],
type text
)
in
WithSource
),
Result =
Table.Combine(Tables)
in
Result
この設計は、概念的にはmapしてからunionする形です。
Source A → Table A
Source B → Table B
Source C → Table C
↓
Table.Combine
Table.Combineは、columns引数を省略した場合、入力Tableの列型の和集合を基に結果を作ります。あるTableにしかない列は、ほかのTableに由来する行ではnullになります。
ただし、列集合が自動的に合わさることと、意味が正規化されることは別です。金額、売上金額、Amountは、Power Queryから見れば異なる列名です。
2.3 中間形:フォルダー表を台帳として残し、Combineする
親テーブルへData列を追加しながら、最後は展開せず、Data列に含まれるTableを結合できます。
let
Files =
Folder.Files(FolderPath),
CsvFiles =
Table.SelectRows(
Files,
each Text.Lower([Extension]) = ".csv"
),
WithData =
Table.AddColumn(
CsvFiles,
"Data",
each
let
Parsed =
fnReadCsv([Content]),
FileName =
[Name],
WithSource =
Table.AddColumn(
Parsed,
"Source.Name",
each FileName,
type text
)
in
WithSource,
type table
),
Result =
Table.Combine(WithData[Data])
in
Result
ファイルの選別と検査はフォルダー表、ファイルごとの変換はData列、最終統合はTable.Combineという役割分担です。管理性と列変動の許容を両立しやすい実務的な形です。
第3章 中間表現を変える
3.1 レコード再構築型:1件の事実を集める
Tableを完成部品とせず、1件の事実を表すRecordまで分解できます。
let
Files =
Folder.Files(FolderPath),
CsvFiles =
Table.SelectRows(
Files,
each Text.Lower([Extension]) = ".csv"
),
Sources =
Table.ToRecords(CsvFiles),
RecordLists =
List.Transform(
Sources,
(Source) =>
let
Parsed =
fnReadCsv(Source[Content]),
Records =
Table.ToRecords(Parsed),
WithSource =
List.Transform(
Records,
(Row) =>
Record.Combine(
{
Row,
[#"Source.Name" = Source[Name]]
}
)
)
in
WithSource
),
AllRecords =
List.Combine(RecordLists),
Result =
Table.FromRecords(AllRecords)
in
Result
処理の形は次のとおりです。
CSV → Table → List of Record
全ファイルのRecordリストを連結
最後にTable.FromRecords
JSON、APIレスポンス、入れ子Record、行ごとに項目が少し異なる半構造化データでは、Tableへ早く固定するよりRecordのリストとして加工する方が自然な場合があります。
3.2 Tableだけがデータではない
Power Queryでは、List、Record、関数も第一級の値です。
Table: 同じ列構造を持つ行集合
List: 同じ順序で処理する値の集合
Record: 名前付きフィールドの集合
Function: 入力から出力を作る変換規則
中間表現を変えると、同じ統合処理でも追加しやすい情報や分岐の置き場所が変わります。
第4章 状態と入力を生成する
4.1 状態遷移型:List.Accumulateはfoldである
List.Accumulateは、前回までの状態と現在の入力から次の状態を作ります。
単純に結合済みTableへ毎回Table.Combineすることもできますが、通常の縦結合では第一候補にしません。反復のたびに、それまでの結合結果を含むTableを再構成する形になりやすいためです。
List.Accumulateを使うなら、状態をRecordとして設計すると目的が明確になります。
let
Files =
Folder.Files(FolderPath),
Sources =
Table.ToRecords(Files),
InitialState =
[
Tables = {},
Errors = {},
FileNumber = 0
],
FinalState =
List.Accumulate(
Sources,
InitialState,
(State, Source) =>
let
Attempt =
try fnReadCsv(Source[Content]),
NextFileNumber =
State[FileNumber] + 1
in
if Attempt[HasError] then
[
Tables = State[Tables],
Errors =
State[Errors]
& {
[
Name = Source[Name],
Error = Attempt[Error]
]
},
FileNumber = NextFileNumber
]
else
[
Tables =
State[Tables] & {Attempt[Value]},
Errors = State[Errors],
FileNumber = NextFileNumber
]
),
Data =
Table.Combine(FinalState[Tables]),
ErrorTable =
Table.FromRecords(FinalState[Errors])
in
[
Data = Data,
Errors = ErrorTable
]
このクエリは、完成Tableだけでなく、正常データとエラー一覧を含むRecordを返します。
状態には、前ファイルの最終残高、全体連番、発見した列名、成功件数、警告一覧、処理ログなども保持できます。入力順序に意味がある場合や、前回結果が次の処理へ影響する場合に適します。
4.2 生成型:List.Generateはunfoldである
入力一覧が最初から存在せず、現在の結果から次の入力を決める場合はList.Generateが適します。代表例はAPIのページ送りです。
let
Pages =
List.Generate(
() =>
[
Page = fnGetPage(null),
Continue = true
],
each [Continue],
(State) =>
let
NextToken =
State[Page][NextToken],
HasNext =
NextToken <> null,
NextPage =
if HasNext then
fnGetPage(NextToken)
else
null
in
[
Page = NextPage,
Continue = HasNext
],
each [Page][Data]
),
Result =
Table.Combine(Pages)
in
Result
List.AccumulateとList.Generateの違いは、入力の所在です。
List.Accumulate
= 与えられた入力を順番に状態へ畳み込む
List.Generate
= 状態から次の候補を作り、条件を満たす間だけ値を生み出す
CSV処理でも、年月を進めながらファイルパスを作る、連番ファイルが存在する間だけ読む、フォルダー階層を条件付きでたどる、といった場面へ応用できます。
第5章 階層・スキーマ・キー・規則で統合する
5.1 分割統治型:Table.Groupで業務上の階層を残す
全ファイルをすぐ1枚の表にせず、会社、年度、拠点、帳票種類などでグループ化し、グループ内だけを結合できます。
let
Files =
Folder.Files(FolderPath),
WithCompany =
Table.AddColumn(
Files,
"Company",
each fnGetCompany([Name]),
type text
),
Grouped =
Table.Group(
WithCompany,
{"Company"},
{
{
"Files",
each _,
type table
}
}
),
WithData =
Table.AddColumn(
Grouped,
"Data",
each
let
Sources =
Table.ToRecords([Files]),
Tables =
List.Transform(
Sources,
each fnReadCsv(_[Content])
)
in
Table.Combine(Tables),
type table
)
in
WithData
この結果では、会社ごとのData列にネストしたTableが残ります。後から展開することも、会社単位の別処理へ渡すこともできます。
5.2 スキーマ先行型:完成形を契約として決める
実務で最も重要なのは、入力の列をそのまま集めることではなく、完成テーブルが持つ列名と型を先に決めることです。
Date date
CustomerCode text
Amount number
SourceName text
各入力を、この契約を満たすTableへ変換してから結合します。
let
ContractColumns =
{"Date", "CustomerCode", "Amount", "SourceName"},
Normalize =
(Source as record) as table =>
let
Parsed =
fnReadCsv(Source[Content]),
Renamed =
Table.RenameColumns(
Parsed,
{
{"売上日", "Date"},
{"得意先コード", "CustomerCode"},
{"売上金額", "Amount"}
},
MissingField.Ignore
),
WithSource =
Table.AddColumn(
Renamed,
"SourceName",
each Source[Name],
type text
),
Shaped =
Table.SelectColumns(
WithSource,
ContractColumns,
MissingField.UseNull
),
Typed =
Table.TransformColumnTypes(
Shaped,
{
{"Date", type date},
{"CustomerCode", type text},
{"Amount", type number},
{"SourceName", type text}
}
)
in
Typed,
Files =
Folder.Files(FolderPath),
Sources =
Table.ToRecords(Files),
NormalizedTables =
List.Transform(Sources, each Normalize(_)),
Result =
Table.Combine(NormalizedTables)
in
Result
年度、部署、取引先ごとに列名が異なる場合や、旧形式と新形式、CSVとExcelとAPIを同じ完成表へ統合する場合に有効です。
5.3 キー統合型:同じ実体の列を増やす
売上明細と顧客マスターは、上下に積むデータではありません。顧客コードをキーとして同じ顧客の情報を結び付けます。
let
Sales =
fnReadSales(),
Customers =
fnReadCustomers(),
Joined =
Table.NestedJoin(
Sales,
{"CustomerCode"},
Customers,
{"CustomerCode"},
"Customer",
JoinKind.LeftOuter
),
Result =
Table.ExpandTableColumn(
Joined,
"Customer",
{"CustomerName", "Area"},
{"CustomerName", "Area"}
)
in
Result
ここでも展開を使いますが、親子展開とは意味が違います。親子展開は1つの入力から生まれた複数行を平らにし、キー統合は別データにある同じ実体の属性を列として追加します。
5.4 規則駆動型:解析関数をデータとして選ぶ
CSV、TSV、JSON、旧形式が混在する場合、ファイル種類に応じて解析関数を切り替えます。
let
Parsers =
[
Csv =
(Source as record) as table =>
fnReadCsv(Source[Content]),
Tsv =
(Source as record) as table =>
let
Parsed =
Csv.Document(
Source[Content],
[
Delimiter = "#(tab)",
Encoding = 65001,
QuoteStyle = QuoteStyle.Csv
]
)
in
Table.PromoteHeaders(Parsed),
Json =
(Source as record) as table =>
Table.FromRecords(
Json.Document(Source[Content])
)
],
ReadSource =
(Source as record) as table =>
let
Parser =
Record.Field(
Parsers,
Source[ParserName]
)
in
Parser(Source)
in
ReadSource
関数をRecordのフィールドとして保持し、ParserNameで取り出しています。区切り文字、文字コード、読み飛ばす行数、ヘッダー行、正規化関数名なども制御テーブルへ持たせられます。
5.5 バイナリ先行型:限定条件でのみ使う
複数BinaryをBinary.Combineし、最後に一度だけCsv.Documentする発想もあります。しかし、一般的な業務CSVの標準解にはしません。
問題になりやすいのは、次の点です。
2ファイル目以降のヘッダー
ファイル末尾の改行不足
UTF-8 BOMが途中へ現れること
文字コード、区切り文字、引用符規則の混在
引用符内改行の境界
全ファイルが厳密に同一形式で、ヘッダー、BOM、改行、文字コードを制御できる場合に限って検討します。
第6章 11の設計パターンを選び分ける
6.1 比較表
| 設計 | 主役 | 中間表現 | 最終操作 | 向いている場面 |
|---|---|---|---|---|
| 親子展開型 | フォルダー表 | Table内のTable | Expand | 外側のファイル情報を残す |
| 部品合成型 | 個々の結果 | List of Table | Table.Combine | 単純な縦結合 |
| 中間形 | フォルダー表と結果Table | Table列 | Table.Combine | 管理性と列変動の両立 |
| レコード再構築型 | 1件の事実 | List of Record | Table.FromRecords | 半構造化データ |
| 状態遷移型 | 処理状態 | Record | List.Accumulate | 前回結果を次へ渡す |
| 生成型 | 次の入力 | 状態Record | List.Generate | ページ送り、未知件数 |
| 分割統治型 | 業務区分 | グループ内Table | Group+Combine | 階層を残す |
| スキーマ先行型 | 完成形の契約 | 正規化済みTable | Table.Combine | 異形式を統合する |
| キー統合型 | 同じ実体のキー | ネスト結合結果 | Join+Expand | マスター属性を付ける |
| 規則駆動型 | メタデータ | 関数Record | 動的関数呼出し | 複数形式を扱う |
| バイナリ先行型 | ファイル内容 | Binary | Binary.Combine | 厳密に同一形式の場合のみ |
6.2 map・flatMap・fold・unfoldで読む
M言語にflatMapやfoldという名前の関数があるわけではありません。一般的な変換の型として対応づけると、個別関数の関係を理解しやすくなります。
map
= 各入力を1つの結果へ変換する
= List.Transform、Table.AddColumn
flatMap
= 各入力を複数行へ変換し、その結果を平らにする
= Table列を追加してTable.ExpandTableColumn
fold
= 入力を順番に処理し、1つの状態へ畳み込む
= List.Accumulate
unfold
= 現在の状態から次の候補と次の状態を作り続ける
= List.Generate
join
= 共通キーで別集合を対応づける
= Table.NestedJoin、Table.Join
group
= 共通区分で小さな集合へ分ける
= Table.Group
6.3 標準の「ファイルの結合」を分解する
Power Queryの画面から「ファイルの結合」を実行すると、サンプルファイル、変換関数、パラメーターなどの補助クエリが生成されます。
内部構造は概ね次の組み合わせです。
代表ファイルで変換手順を作る
↓
変換手順を関数化する
↓
各ファイルへ関数を適用する
↓
戻り値のTableを展開する
つまり、関数適用と親子展開型の組み合わせとして読めます。自動生成クエリも、主語と中間表現へ分解すれば修正箇所を判断しやすくなります。
第7章 実務で壊れにくくする
7.1 由来情報を早い段階で残す
結合後に異常行が見つかっても、元ファイルが分からなければ調査できません。少なくとも次のいずれかを完成表へ残します。
Source.Name
Folder Path
ファイル順または業務上の取込番号
取込日時
7.2 列名の統合と意味の正規化を区別する
Table.Combineは、列名から業務上の意味を推測しません。同じ意味の列が異なる名前なら、結合前に改名します。逆に、同じ列名でも意味や単位が異なるなら、安易に同一列へ結合してはいけません。
7.3 型変換の場所を決める
型変換には二つの代表的な方針があります。
各ファイルで型を確定してから結合する
この方法は、どのファイルで変換に失敗したかを特定しやすくなります。
各ファイルでは文字列中心で読み、結合後に最終型を設定する
この方法は、全体へ一貫した型を適用しやすくなります。どちらの場合も、暗黙の型推測へ任せず、完成スキーマとエラー方針を決めます。
7.4 Fail FastとQuarantineを選ぶ
1ファイルの異常で全体を停止するか、正常分と異常一覧を分けるかは業務要件です。
Fail Fast
= 1ファイルでも異常なら全体をエラーにする
Quarantine
= 正常ファイルは統合し、異常ファイルは別一覧へ隔離する
欠損を許さない確定処理ではFail Fast、日次取込の早期確認ではQuarantineが適する場合があります。
7.5 List.Accumulateを高速化関数とみなさない
List.Accumulateは状態遷移を表現する関数です。使用しただけでストリーム処理になったり、メモリ使用量が小さくなったりするわけではありません。
単純結合なら、Tableのリストを作って最後に一度だけTable.Combineする形を先に検討します。性能差を主張する場合は、Power Query診断や同一データによる実測を使います。
7.6 Table.Bufferを習慣的に追加しない
Table.Bufferは、テーブルをメモリへ読み込み、評価中の外部変化から分離します。しかし、読み込みと保持のコストが増え、後続のクエリフォールディングを妨げることがあります。
速くなる場合も遅くなる場合もあるため、再評価の有無や診断結果を確認せず、フォルダー結合へ機械的に追加しません。
7.7 空と境界を設計する
正常な複数CSVだけでなく、次の状態を設計対象にします。
対象CSVが0件
ヘッダーだけでデータ行が0件
必須列が存在しない
0バイトファイル
文字コードが異なる
読み取り中の一時ファイル
列が追加または削除された
エラーにするのか、空Tableを返すのか、警告へ隔離するのかを決めます。
第8章 通常の業務CSVに対する推奨構成
8.1 第一候補となる流れ
通常の業務CSVでは、次の順序を第一候補にできます。
Folder.Files
↓
拡張子、隠し属性、ファイル名で対象を絞る
↓
Table.ToRecordsでファイルをRecordのリストにする
↓
ファイル単位の関数で解析、ヘッダー昇格、列名正規化を行う
↓
Source.Nameを結果へ追加する
↓
完成スキーマへそろえる
↓
Table.Combineを一度だけ実行する
これは、部品合成型、スキーマ先行型、由来情報付与の組み合わせです。
8.2 例外があるときの切り替え
| 条件 | 選ぶ設計 |
|---|---|
| フォルダー属性を広く引き継ぐ | 親子展開型 |
| 前ファイルの結果が次へ影響する | 状態遷移型 |
| 入力一覧が最初には分からない | 生成型 |
| 会社や年度の階層を残す | 分割統治型 |
| CSVごとに形式が異なる | 規則駆動型+スキーマ先行型 |
| マスター情報を加える | キー統合型 |
| 半構造化された行を扱う | レコード再構築型 |
8.3 設計レビューで確認する質問
実装前またはレビュー時には、次の質問を使えます。
1つの入力とは何か。
解析結果はTable、List、Recordのどれか。
元ファイルの文脈はどこへ保持するか。
完成表の列名と型は決まっているか。
列差分は許容するのか、異常とするのか。
1ファイルの失敗で全体を止めるのか。
入力順序や前回状態に意味があるか。
最後に行を増やすのか、列を増やすのか、階層を残すのか。
空フォルダー、空CSV、0バイトをどう扱うか。
性能に関する主張を実測したか。
まとめ 関数ではなく主語とデータの形を選ぶ
複数データを一つにまとめる方法に、唯一の正解はありません。ただし、選択の基準は整理できます。
外側の文脈を残す
→ AddColumnしてExpandする
個々の結果を同格の部品として扱う
→ List.TransformしてTable.Combineする
1件の事実へ分解して再構築する
→ Recordを集めてTable.FromRecordsする
前回の状態を引き継ぐ
→ List.Accumulateする
次の入力を状態から作る
→ List.Generateする
業務上のまとまりを残す
→ Table.Groupで分けてからCombineする
完成形を中心に設計する
→ 共通スキーマへ正規化してからCombineする
同じ実体の情報を合わせる
→ キーでJoinする
Power Queryを画面操作や関数カタログとして覚えるだけでは、設計は画一的になります。入力単位、中間表現、引き継ぐ文脈、完成形、最終演算を独立して選ぶと、同じCSV結合からTable、List、Record、関数、状態、階層、スキーマというM言語の主要概念が見えてきます。
一つにまとめるとは、すべてを早い段階で平らにすることではありません。業務上の意味を失わない段階まで構造を保ち、最終的に必要な形へ変換することです。
参考資料
Microsoft Learn「Power Query M formula language」
Microsoft Learn「Folder.Files」
Microsoft Learn「Table.AddColumn」
Microsoft Learn「Table.ExpandTableColumn」
Microsoft Learn「Table.Combine」
Microsoft Learn「Table.ToRecords」
Microsoft Learn「Table.FromRecords」
Microsoft Learn「List.Transform」
Microsoft Learn「List.Combine」
Microsoft Learn「List.Accumulate」
Microsoft Learn「List.Generate」
Microsoft Learn「Table.Group」
Microsoft Learn「Table.NestedJoin」
Microsoft Learn「Record.Combine」
Microsoft Learn「Table.Buffer」
出典メモ
元原稿: PowerQuery_複数ソースを一つにまとめる設計パターン.md
元原稿の28節に含まれる11の設計パターン、コード、比較、注意点を省略せず、公開記事として「主語・中間表現・文脈・完成形・最終演算」という一本の設計軸へ再構成した。
Power Query M関数の仕様は、2026年8月9日にMicrosoft LearnのM言語リファレンス、Table.Combine、List.Combine、List.Accumulate、List.Generate、Record.Combine、Table.Bufferなどのページで確認した。
性能はデータ量、データソース、評価、キャッシュ、フォールディングによって変わるため、List.Accumulate、Table.Combine、Table.Bufferの優劣を実測なしに断定していない。
