Power QueryのTable.Schemaで列の構造を調べる ― 必須列の欠落を取り込み前に検出

VBA・Officeカテゴリを表すパンダのイラスト VBA・Office

この記事について
この記事は、生成AIを活用した自動生成フローで作成しています。Microsoft Learn の Table.Schema、Table.ColumnNames、Table.HasColumns、Table.FromRows の仕様を確認し、ダミー表を使って列の情報を取り出すPower Query Mの例を整理しました。

検証ステータス:📘 Microsoft公式仕様確認済み・Power Query実機未確認
以下の表や結果は公式仕様から導いた期待値です。ExcelやPower BIでの実行確認はまだ行っていません。

毎月届くCSVや部署ごとに作られたExcel表をPower Queryで取り込むとき、厄介なのは「データが空」だけではありません。前月まであった列が消えた、列名が変更された、金額列が文字列として認識された、といった表の構造の変化も処理失敗の原因になります。

Power Query Mには、表の構造を調べる Table.Schema という関数があります。表示できるのは列名だけではなく、列の位置、データ型に関する情報、nullを許容するかどうかなどです。 、3行のダミー表で構造を観察し、列が欠けたケースで処理を止める方法、列の有無を真偽値で判定する方法まで紹介します。

Table.Schemaは何を返すのか

基本構文は次のとおりです。

Table.Schema(table as table) as table

この関数は、元データの各行を返すのではなく、元テーブルの列を1行ずつ説明した別のテーブルを返します。たとえば元の表が「注文ID」「部署」「金額」の3列なら、スキーマ側には原則その3列に対応する情報が並びます。

スキーマの列読み取れること
Name元の列名
Position元の列位置。先頭は0
TypeName型名
Kind型の種類
IsNullablenullを含められる型として宣言されているか
NativeTypeName元データベースなどでのネイティブ型名(取得可能な場合)

このほか精度や最大長などの情報もありますが、ソースによって取得できない項目があります。メタデータが空欄だからといって、直ちにデータ破損と断定することはできません。

公式仕様:Microsoft Learn — Table.Schema

Excelから試す方法

ExcelのPower Queryエディターで「空のクエリ」を作り、詳細エディターに次のMコードを貼り付けます。外部ファイルの読み込みも、データベースへの接続も不要です。

let
    Source = Table.FromRows(
        {
            {1001, "Sales", 1250.5},
            {1002, "Support", 900.0},
            {1003, "Sales", 0.0}
        },
        type table [
            OrderId = Int64.Type,
            Department = text,
            Amount = number
        ]
    ),
    Schema = Table.Schema(Source),
    ImportantFields = Table.SelectColumns(
        Schema,
        {"Name", "Position", "TypeName", "Kind", "IsNullable"}
    )
in
    ImportantFields

ここで Table.FromRows は、行データのリストからテーブルを作っています。2番目の引数には列名だけでなく type table [...] というテーブル型を与えています。そのため、サンプルでは「OrderIdが整数、Departmentがテキスト、Amountが数値」という型宣言を持たせています。

Table.Schema(Source) だけなら、取得可能なスキーマ列が多数出ます。今回は見やすいように Table.SelectColumns で5項目だけ残しています。

表示される情報の見方

期待する元列の並びは次のとおりです。

NamePosition型の意味
OrderId0整数
Department1文字列
Amount2数値

実際の TypeName や Kind の表現は、Power Queryのエンジンやソースの型表現に依存します。上の「型の意味」は読み方の説明であり、型名欄の実出力を一字一句再現したものではありません。

重要なのは Positionは0から始まる という点です。Excelの列番号を数えるつもりで1から考えないようにしてください。

1か所変えて観察する

まず最後の Amount = number を、次のように変更してみます。

type table [
    OrderId = Int64.Type,
    Department = text,
    Amount = text
]

このまま実行すると、元のサンプルには数値の値が入っていても、テーブルの型宣言をtextに変えた影響をスキーマで確認することになります。これは「実際のデータ値の型チェック」と「列に宣言した型情報を見ること」の違いを考える実験です。

注意: 型の宣言を変えただけで、既存の値がすべて望みどおり安全に変換されたと判断してはいけません。値が期待した形式か、変換エラーがないかは別途検査する必要があります。

列が消えたとき、後続処理を止める

月次CSVで毎回必要な列が OrderId と Amount だったとします。担当部署から届いたデータに Amount がなければ、それを見逃して集計を続けるべきではありません。

次の例は、必要な列と実際に存在する列を比較します。前のクエリとは別の空クエリとして実行してください。

let
    Source = Table.FromRows(
        {
            {1001, "Sales"},
            {1002, "Support"}
        },
        type table [OrderId = Int64.Type, Department = text]
    ),
    Required = {"OrderId", "Amount"},
    Existing = Table.ColumnNames(Source),
    Missing = List.Difference(Required, Existing),
    Checked =
        if List.IsEmpty(Missing)
        then Source
        else error (
            "Required column(s) missing: "
            & Text.Combine(Missing, ", ")
        )
in
    Checked

ここでは実際の列が {"OrderId", "Department"} で、必要な列が {"OrderId", "Amount"} です。

List.Difference(Required, Existing) は、必要なのに存在しない列だけを取り出します。その結果が {"Amount"} なので、条件により処理は次のエラーになる想定です。

Required column(s) missing: Amount

「金額列がないなら、残りの列だけ集計する」といった静かな誤集計を防ぐ目的で利用できます。

ただしこの方法は、データソース自体の障害や認証失敗まで吸収するものではありません。列情報を取得する前に接続が失敗した場合は、その接続エラーを別に調査する必要があります。

真偽値だけを取得する場合はTable.HasColumns

列の詳細情報が必要なく「必要な列が存在するかどうか」だけを判定したいなら、もっと短い関数があります。

Table.HasColumns(table as table, columns as any) as logical

この関数は、指定した列がすべて存在するときtrue、1つでも欠けるとfalseを返します。

let
    Source = #table(
        type table [OrderId = Int64.Type, Amount = number],
        {{1001, 12.5}, {1002, 18.0}}
    ),
    HasRequired = Table.HasColumns(Source, {"OrderId", "Amount"}),
    HasOptional = Table.HasColumns(Source, {"OrderId", "Owner"})
in
    #table(

        type table [Check = text, Exists = logical],
        {
            {"OrderId + Amount", HasRequired},
            {"OrderId + Owner", HasOptional}
        }
    )

期待結果は次のとおりです。

CheckExists
OrderId + Amounttrue
OrderId + Ownerfalse

公式仕様:Microsoft Learn — Table.HasColumns

3つの関数をどう使い分ける?

関数返り値向いている目的
Table.ColumnNames列名のlist列名の差分を調べる
Table.HasColumnstrue / false必須列の存在判定
Table.Schema列情報のtable型や位置などの構造の調査

Table.Schema が常に最適というわけではありません。必要なのが有無だけなら Table.HasColumns で足ります。一方、CSVやDBの仕様変更を調査するなら Table.Schema が有効です。

実際のCSV取込みへ応用するとき

現場では、次の順で検査する形にすると原因を切り分けやすくなります。

  1. データソースへ接続できるか

  2. 必須の列名がすべて存在するか

  3. 各列に設定された型が期待したものか

  4. 必要な型変換でエラーが発生しないか

  5. 必要なキー列にnullや重複がないか

  6. 件数や金額の集計結果が妥当か

Table.Schema は3番目の構造確認の材料であり、4〜6を自動的に証明してくれる関数ではありません。

例えば Amount が数値型として宣言されていても、外部のCSVに「不明」「1,200円」といった文字列が混入していたら、どこかの型変換工程で失敗する可能性があります。型情報だけを見て「すべての金額が正しい」とは判断しないでください。

また、CSVの列名が前後の空白、全角と半角、見た目が似た文字によって変わっている場合、単なる列名の一致判定では通りません。そもそもどういう列名を正式とするか、データ受渡しのルールを定める必要があります。

毎月の処理に組み込む判断

良い使い方は、毎月のファイルを取り込む最初の段階で必須列の有無を検査し、条件を満たさないデータは読み込まず、担当者が入力仕様の違いを確認できるようにすることです。

避けたい使い方は、何でも try ... otherwise で握りつぶして、列がなくても空欄のまま処理を進めることです。業務上「列がなくてもよい」と決められている場合を除き、異常を隠すと集計ミスに気付きにくくなります。

列順が変わっても列名で選択できる実装を基本にすると、位置の変更による影響を減らせます。ただし、同名列の扱いなど、コネクタによる具体的な挙動も確認してください。

GitHubに置いたサンプル

check-schema.pq には、この記事で使った独立した3つのクエリをまとめました。各クエリを別々に詳細エディターへ貼り付けてください。 3つの let ... in をそのままひと続きに貼るためのスクリプトではありません。

実機で試したときは、ExcelまたはPower BIのバージョン、表示された TypeName、エラーの内容を記録しておくと、再現性のある検証記録になります。

参照したMicrosoft公式情報

文書情報

記事タイトル
Power QueryのTable.Schemaで列の構造を調べる ― 必須列の欠落を取り込み前に検出
作成日
更新日
Source URL
https://papanda925.com/?p=18107

ライセンス: 本記事のうち、当サイトが権利を有する本文・自作図表は、特記なき限り CC BY 4.0 で利用できます。生成AIを活用して作成・編集した内容を含みます。コードについて、別途ライセンス表示またはリンク先GitHubリポジトリのライセンスがある場合は、その条件を優先します。引用・第三者資料・画像・商標等は本ライセンスの対象外です。 利用ポリシー

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