ゴールのイメージをそろえる
今回のテーマは「フォルダ内の複数ファイルを一括取込するときに、“壊れているファイル”だけを自動でスキップして、クエリ全体を止めない実務テンプレ」です。
壊れたファイルが1つ混ざっているだけで、全部の取り込みがエラーで止まる——これを「そのファイルだけ飛ばして、他は普通に読み込む」状態にしたい、という話です。
キーワードは Power Query の try ... otherwise(エラー処理)と、HasError/Value です。
ここを押さえると、「壊れたファイルを自動スキップ」はパターン化できます。
まず「壊れたファイル」とは何かを整理する
実務でよくある「壊れたファイル」のパターン
イメージしやすい例を挙げると、こんな感じです。
本当は CSV のはずなのに、実際は中身が Excel だった。
CSV の区切りや文字コードが想定と違い、Csv.Document がエラーになる。
Excel ブックが破損していて、Excel.Workbook がエラーになる。
Power Query 的には、「そのファイルをテーブルに変換しようとしたときにエラーになるもの」が“壊れたファイル”です。
なので、「変換処理を try で包んで、エラーになったものだけ後で除外する」というのが基本戦略になります。
超重要:Power Query の try / otherwise の考え方
try の戻り値は「エラーかどうか+中身」のセット
try は「この式を実行してみて、成功したら結果を、失敗したらエラー情報を返す」という仕組みです。
例えば、
try 1 / 0
Power Queryは、普通ならエラーですが、try を付けると「エラー情報を持ったレコード」が返ってきます。try 1 / 2 のように成功する場合は、「HasError = false」「Value = 0.5」のようなレコードになります。
つまり、try 式 の結果は、
結果.HasError…エラーかどうか(true / false)結果.Value…成功したときの値(テーブルなど)
という2つの情報を持ったレコードだ、と覚えておくと分かりやすいです。
otherwise を使う書き方もありますが、「壊れたファイルをスキップしたい」場合は、try の結果をそのまま列に入れておき、後で HasError を見てフィルタする方が柔軟です。
例題1:フォルダ内 CSV 一括取込で「壊れた CSV」を自動スキップ
想定する状況
C:\Data\DailyCsv に、毎日の CSV が溜まっているとします。
ところが、たまに中身が変なファイル(文字コードが違う、区切りが違う、実は CSV じゃない)が混ざり、Csv.Document がエラーになってクエリ全体が止まってしまう。
これを、「壊れたファイルはスキップして、正常なファイルだけ結合する」ようにしたい、という状況です。
実務テンプレ M コード(CSV 版)
let
// 1) フォルダ内のファイル一覧を取得
Source = Folder.Files("C:\Data\DailyCsv"),
// 2) .csv だけに絞り込む
OnlyCsv =
Table.SelectRows(
Source,
each Text.Lower([Extension]) = ".csv"
),
// 3) 各ファイルを「try 付き」で CSV テーブルに変換
WithTry =
Table.AddColumn(
OnlyCsv,
"CsvTry",
each
try
Csv.Document(
[Content],
[
Delimiter = ",",
Encoding = 65001,
QuoteStyle = QuoteStyle.Csv
]
),
type any
),
// 4) エラーになったファイル(HasError = true)を確認したければここで見られる
// 5) 正常に読めたものだけに絞り込む
SuccessOnly =
Table.SelectRows(
WithTry,
each [CsvTry][HasError] = false
),
// 6) 成功した Value(テーブル)だけを取り出す列を追加
WithTable =
Table.AddColumn(
SuccessOnly,
"CsvTable",
each [CsvTry][Value],
type table
),
// 7) 代表テーブルから列名を取得
SampleTable = WithTable[CsvTable]{0},
ColNames = Table.ColumnNames(SampleTable),
// 8) CsvTable を展開して、全ファイル分を縦に結合
Combined =
Table.ExpandTableColumn(
WithTable,
"CsvTable",
ColNames,
ColNames
)
in
Combined
Power Query流れを言葉で整理すると、こうです。
各ファイルに対して Csv.Document を「try 付き」で実行し、その結果(成功 or エラー)を CsvTry 列に入れる。
CsvTry[HasError] が false の行だけ残す(壊れたファイルはここで落ちる)。
CsvTry[Value](成功したときのテーブル)を CsvTable 列として取り出す。
最後に CsvTable を展開して結合する。
ここでの超重要ポイントは、「エラーをその場で潰すのではなく、try の結果を一度列に持たせてから、HasError で判定している」ことです。
これにより、「どのファイルが壊れていたか」を後から確認することもできます(WithTry の段階で Name と一緒に見ればOK)。
例題2:フォルダ内 Excel 一括取込で「壊れたブック」を自動スキップ
想定する状況
C:\Data\MonthlyBooks に、毎月の売上ブックが溜まっているとします。
ところが、たまに破損した Excel ファイルや、パスワード付きで開けないファイルが混ざる。Excel.Workbook がエラーになり、クエリ全体が止まってしまう。
これを、「壊れたブックはスキップして、正常なブックだけ結合する」ようにしたい、という状況です。
実務テンプレ M コード(Excel 版・1枚目シートを読む例)
let
// 1) フォルダ内のファイル一覧を取得
Source = Folder.Files("C:\Data\MonthlyBooks"),
// 2) .xlsx だけに絞り込む
OnlyXlsx =
Table.SelectRows(
Source,
each Text.Lower([Extension]) = ".xlsx"
),
// 3) 各ブックの 1 枚目シートを「try 付き」で読み込む
WithTry =
Table.AddColumn(
OnlyXlsx,
"SheetTry",
each
try
let
wb = Excel.Workbook([Content], true, true),
firstSheetRow =
Table.SelectRows(wb, each [Kind] = "Sheet"){0},
firstSheetTable = firstSheetRow[Data],
promoted =
Table.PromoteHeaders(
firstSheetTable,
[PromoteAllScalars = true]
)
in
promoted,
type any
),
// 4) 正常に読めたブックだけに絞り込む
SuccessOnly =
Table.SelectRows(
WithTry,
each [SheetTry][HasError] = false
),
// 5) 成功した Value(テーブル)を取り出す
WithTable =
Table.AddColumn(
SuccessOnly,
"SheetTable",
each [SheetTry][Value],
type table
),
// 6) 代表テーブルから列名を取得
SampleTable = WithTable[SheetTable]{0},
ColNames = Table.ColumnNames(SampleTable),
// 7) SheetTable を展開して、全ブック分を縦に結合
Combined =
Table.ExpandTableColumn(
WithTable,
"SheetTable",
ColNames,
ColNames
)
in
Combined
Power Queryここでも流れは CSV 版と同じです。
Excel.Workbook 〜 ヘッダー昇格までの処理を、丸ごと try ... in promoted で包む。
SheetTry[HasError] が false の行だけ残す。
SheetTry[Value] を SheetTable として取り出し、最後に展開する。
壊れたブックや、シート構造が想定と違ってエラーになるブックは、HasError = true になり、この時点で自動的にスキップされます。
重要ポイントの深掘り
try … otherwise との違いと使い分け
try には、もう一つの書き方として try 式 otherwise 代替値 があります。
例えば、
try Csv.Document([Content], ...) otherwise null
Power Queryと書くと、「エラーなら null を返す」という動きになります。
この場合、列には「テーブル」か「null」が入ることになります。
その後で、
Table.SelectRows(WithTable, each [CsvTable] <> null)
Power Queryのようにして「null を除外する」というパターンもあります。
どちらでも目的は達成できますが、実務テンプレとしては
エラーの詳細を見たい → try の結果(HasError / Error / Value)をそのまま列に持つ
とにかくスキップできればいい → try ... otherwise null で簡略化
という使い分けがしやすいです。
初心者のうちは、まずは「HasError / Value を使うパターン」で慣れておくと、
「何が起きているか」を目で確認しやすくておすすめです。
「壊れたファイル名」をログ的に残すこともできる
WithTry の段階では、Name 列(ファイル名)と SheetTry / CsvTry 列(try の結果)が並んでいます。
ここから「HasError = true の行だけ」を別クエリとして残しておけば、
どのファイルが壊れていたか
何回連続で壊れているか
といった“エラーログ”としても使えます。
例えば、こんな感じです。
ErrorOnly =
Table.SelectRows(
WithTry,
each [SheetTry][HasError] = true
)
Power Queryこれを別クエリとしてシートに出しておけば、
「壊れたファイル一覧」を Excel 上で確認できるようになります。
実務テンプレとしてのまとめ
「壊れたファイルを自動スキップ」の型は、こう整理できます。
ファイルごとの変換処理(Csv.Document や Excel.Workbook〜ヘッダー昇格)を、丸ごと try ... in で包む。
その結果を列に持たせ、HasError で正常/エラーを判定する。
正常なものだけ Value を取り出して結合する。
一度この型を覚えてしまえば、CSV でも Excel でも、
「中で何をしているか」だけ変えて、同じノリで使い回せます。
