Power Query 実務テンプレ | データ取込・更新系:空ファイルを自動除外

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

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

今回のテーマは「フォルダ内の複数ファイルを一括取込するときに、“中身が空のファイル”だけを自動で除外する実務テンプレ」です。
現場だと、こんなことがよく起きます。

フォルダに「まだ中身が入っていないテンプレファイル」も置かれている。
システムが“中身ゼロのCSV”を出力してくることがある。

これらをそのまま読み込むと、列だけあって行がゼロのテーブルが混ざったり、ヘッダーすら無くてエラーになったりします。
それを Power Query 側で「空ならスキップする」という型にしておく、というのが今回のゴールです。


まず「空ファイル」をどう定義するか

実務でよく使う二つの定義

空ファイルの定義は、ざっくり次のどちらかになります。

ファイルサイズがほぼゼロ(バイト数で判定)。
中身をテーブルにしたときに、データ行が1行もない(行数で判定)。

一番軽いのは「ファイルサイズで弾く」やり方です。
ただし、「ヘッダーだけあるけどデータがない」ファイルはサイズがそこそこあるので、
それも除外したい場合は「行数で判定する」方が確実です。

この二つを、CSV と Excel のフォルダ一括取込の流れに組み込んでいきます。


パターン1:CSV の空ファイルを自動除外するテンプレ

例題の前提

C:\Data\DailyCsv フォルダに、毎日こんなファイルが溜まっていくとします。

sales_2024-10-01.csv
sales_2024-10-02.csv

ところが、たまに「中身が空のファイル」や「ヘッダーだけでデータ行ゼロのファイル」が混ざる。
これらを自動で除外して、データがあるファイルだけを結合したい、という状況です。

ファイルサイズでざっくり除外するテンプレ

まずは一番軽い「サイズ判定」から。

let
    Source = Folder.Files("C:\Data\DailyCsv"),

    OnlyCsv =
        Table.SelectRows(
            Source,
            each Text.Lower([Extension]) = ".csv"
        ),

    // 1KB 未満のファイルを「空」とみなして除外する例
    NonEmptySize =
        Table.SelectRows(
            OnlyCsv,
            each [Size] > 0
        ),

    AddedCsvTable =
        Table.AddColumn(
            NonEmptySize,
            "CsvTable",
            each
                Csv.Document(
                    [Content],
                    [
                        Delimiter = ",",
                        Encoding = 65001,
                        QuoteStyle = QuoteStyle.Csv
                    ]
                ),
            type table
        )
in
    AddedCsvTable
Power Query

ここでのポイントは [Size] > 0 の部分です。
Size はバイト数なので、0 のファイルは完全に空です。
「ヘッダーだけあるファイル」も除外したいなら、サイズの閾値をもう少し大きくしても構いません。

ただし、サイズ判定だけだと「ヘッダーだけのファイル」は残ってしまうことがあります。
そこで、より確実な「行数判定」のパターンも押さえておきます。

行数で「中身ゼロ」を判定して除外するテンプレ

CSV をテーブル化したあとで、「データ行が1行もないテーブル」を除外するパターンです。

let
    Source = Folder.Files("C:\Data\DailyCsv"),

    OnlyCsv =
        Table.SelectRows(
            Source,
            each Text.Lower([Extension]) = ".csv"
        ),

    // 各ファイルをテーブル化
    AddedCsvTable =
        Table.AddColumn(
            OnlyCsv,
            "CsvTableRaw",
            each
                Csv.Document(
                    [Content],
                    [
                        Delimiter = ",",
                        Encoding = 65001,
                        QuoteStyle = QuoteStyle.Csv
                    ]
                ),
            type table
        ),

    // 先頭行をヘッダーに昇格
    WithHeader =
        Table.TransformColumns(
            AddedCsvTable,
            {
                "CsvTableRaw",
                each
                    Table.PromoteHeaders(
                        _,
                        [PromoteAllScalars = true]
                    ),
                type table
            }
        ),

    // 行数を数える列を追加
    WithRowCount =
        Table.AddColumn(
            WithHeader,
            "行数",
            each Table.RowCount([CsvTableRaw]),
            Int64.Type
        ),

    // 行数が 0 のファイル(完全に空)を除外
    NonEmptyOnly =
        Table.SelectRows(
            WithRowCount,
            each [行数] > 0
        )
in
    NonEmptyOnly
Power Query

この時点で、CsvTableRaw 列には「1行以上データがあるテーブル」だけが残っています。
あとは、いつも通り列名を取得して展開すれば、空ファイルを自動除外した結合テーブルが作れます。

ここでの重要ポイントは「Table.RowCount を使って、テーブルの行数で判定している」ことです。
これなら、サイズが小さくても中身があれば残るし、ヘッダーだけでデータ行ゼロならきちんと除外できます。


パターン2:Excel の空ブック/空シートを自動除外するテンプレ

例題の前提

C:\Data\MonthlyBooks に、毎月の売上ブックが溜まっているとします。
どのブックも「1枚目のシートに売上明細が入る」想定ですが、
たまに「テンプレだけでまだ入力されていないブック」や「シートはあるけどデータ行ゼロ」のものが混ざる。

これらを自動でスキップして、データがあるブックだけを結合したい、という状況です。

1枚目シートの行数で判定して除外するテンプレ

let
    Source = Folder.Files("C:\Data\MonthlyBooks"),

    OnlyXlsx =
        Table.SelectRows(
            Source,
            each Text.Lower([Extension]) = ".xlsx"
        ),

    // 各ブックの 1 枚目シートを読み込む
    WithSheetTable =
        Table.AddColumn(
            OnlyXlsx,
            "SheetTableRaw",
            each
                let
                    wb = Excel.Workbook([Content], true, true),
                    firstSheetRow =
                        Table.SelectRows(wb, each [Kind] = "Sheet"){0},
                    firstSheetTable = firstSheetRow[Data]
                in
                    firstSheetTable,
            type table
        ),

    // 行数を数える列を追加
    WithRowCount =
        Table.AddColumn(
            WithSheetTable,
            "行数",
            each Table.RowCount([SheetTableRaw]),
            Int64.Type
        ),

    // 行数が 0 のブック(完全に空)を除外
    NonEmptyOnly =
        Table.SelectRows(
            WithRowCount,
            each [行数] > 0
        ),

    // 先頭行をヘッダーに昇格
    WithHeader =
        Table.TransformColumns(
            NonEmptyOnly,
            {
                "SheetTableRaw",
                each
                    Table.PromoteHeaders(
                        _,
                        [PromoteAllScalars = true]
                    ),
                type table
            }
        )
in
    WithHeader
Power Query

このテンプレでは、「1枚目シートの行数が 0 のブック」を空とみなして除外しています。
もし「ヘッダーだけあってデータ行がない」ブックも除外したいなら、
ヘッダー昇格後に「行数 > 0」ではなく「行数 > 1」などに変える、という考え方もできます。

ここでの重要ポイントは、「Excel.Workbook → Kind = ‘Sheet’ でシートを特定 → Data を取り出す → Table.RowCount で行数判定」という流れを型として覚えることです。


どこで「空判定」するのが一番ラクか

ファイル一覧の段階で判定するか、中身をテーブルにしてから判定するか

ざっくり分けると、空判定のタイミングは二つあります。

フォルダからファイル一覧を取った直後に、Size や Date modified などで判定する。
Content をテーブル化したあとで、Table.RowCount で判定する。

前者(サイズ判定)は軽くて速いですが、「ヘッダーだけあるファイル」を除外しにくい。
後者(行数判定)は少し重くなりますが、「本当にデータがあるかどうか」で判定できるので確実です。

実務テンプレとしては、

まずサイズで明らかに空なものを落とす(Size = 0)。
そのうえで、必要なら行数判定も入れる。

という二段構えにしておくと、パフォーマンスと確実性のバランスが取りやすくなります。


実務テンプレとしてのまとめイメージ

空ファイル自動除外の型は、こう整理できます。

フォルダ一括取込の流れの中で、「空判定用の列(行数やサイズ)」を一度追加する。
その列を使って「行数 > 0」「Size > 0」のようにフィルタし、空ファイル由来の行を丸ごと落とす。

一度この型を作っておけば、CSV でも Excel でも、
「Table.RowCount の対象」と「どの段階で判定するか」だけ変えれば、ほぼ同じノリで使い回せます。

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