Power Query 実務テンプレ | データ取込・更新系:壊れたファイルを自動スキップ

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

ゴールのイメージをそろえる

今回のテーマは「フォルダ内の複数ファイルを一括取込するときに、“壊れているファイル”だけを自動でスキップして、クエリ全体を止めない実務テンプレ」です。
壊れたファイルが1つ混ざっているだけで、全部の取り込みがエラーで止まる——これを「そのファイルだけ飛ばして、他は普通に読み込む」状態にしたい、という話です。

キーワードは Power Query の try ... otherwise(エラー処理)と、HasErrorValue です。
ここを押さえると、「壊れたファイルを自動スキップ」はパターン化できます。


まず「壊れたファイル」とは何かを整理する

実務でよくある「壊れたファイル」のパターン

イメージしやすい例を挙げると、こんな感じです。

本当は 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 でも、
「中で何をしているか」だけ変えて、同じノリで使い回せます。

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