Power QueryでJSONを読み込むと、最初は表ではなく「Record」「List」と書かれたセルが並びます。これを順に展開すれば表になります。ただ、どこまで展開するか、どの列を行に広げるかを決めずに進めると、行が想定より増えたり、nullだらけの列ができたりします。

この記事では、サンプルのJSONを使って次の内容を説明します。

  • RecordとListの見分け方
  • 展開の順番
  • 行が増える箇所とnullの確かめ方

M言語の文法全般は別の記事で扱います。

先に「1行を何の1件にするか」を決める

例として、次のような注文データを使います。

{
  "orders": [
    {
      "id": "A001",
      "date": "2026-09-01",
      "customer": { "code": "C01", "name": "取引先A" },
      "items": [
        { "sku": "P-100", "qty": 2 },
        { "sku": "P-200", "qty": 1 }
      ]
    },
    {
      "id": "A002",
      "date": "2026-09-02",
      "customer": { "code": "C02", "name": "取引先B" },
      "items": []
    }
  ]
}

このJSONには「注文」と「明細」の2つの単位があります。1行を注文にするか明細にするかで、展開の仕方が変わります。

1行の単位 itemsの扱い 行数
注文 行には展開しない(件数だけ数える、または別のクエリにする) 注文数と同じ
明細 新しい行に展開する 明細数(空の注文をどう扱うかで変わる)

両方が必要なら、注文の表と明細の表を別々のクエリにして、idで結びつけるのがおすすめです。注文情報が明細の数だけ繰り返される1枚の表より、集計や確認がしやすくなります。

RecordとListを見分ける

エディターの表示 意味 JSONでの形 次にする操作
Record 項目名と値の組(1件分) { } 列として展開する
List 値の並び [ ] テーブルへの変換、新しい行に展開、値の抽出
Table すでに表になっている ― 展開する
文字・数値 値そのもの ― そのまま使う

考え方は単純です。Recordは横(列)に広げ、Listは縦(行)に広げるか1つのセルにまとめます。

手順1:JSONを読み込む

Excelの「データ」タブから「データの取得」→「ファイルから」→「JSONから」を選び、ファイルを指定します。メニューの名前や位置はExcelのバージョンで多少違うことがあります。

Web APIの応答を読む場合は、「データの取得」の「その他のデータソースから」→「Webから」でURLを指定します。認証方法や必要なパラメーターは、APIの提供元の仕様書で確認してください。

読み込むとPower Queryエディターが開きます。表示はJSONの最上位の形で変わります。

  • 最上位がRecord(上の例):orders などの項目名と、その値(List)が並ぶ
  • 最上位がList:Listの中身が並ぶ(多くの場合、1件ずつRecord)

手順2:表にしたい配列までたどる

上の例では、orders の行にある「List」の文字をクリックします。そのListの中身に移動するステップが追加され、Recordが縦に並んだ一覧になります。

最上位がListの場合、この手順はいりません。

手順3:Listをテーブルに変換する

「リスト ツール」の「変換」タブで「テーブルへの変換」を選びます。区切り記号は「なし」のまま、その他も既定のまま「OK」を押します。

1列(Column1)にRecordが並んだ表になります。

手順4:Recordの列を展開する

列見出しの右にある展開ボタン(左右を向いた矢印のアイコン)を押し、取り出す項目にチェックを入れます。

  • 「元の列名をプレフィックスとして使用します」をオフにすると、Column1.id のような列名にならない
  • 別の階層にも同じ名前の項目がある場合は、オンにして区別するか、あとで列名を変える

展開する項目の一覧は、先頭の一部の行だけから作られることがあります。「リストが不完全な可能性があります」と表示されたら、「さらに読み込む」を押してください。後ろの行にしかない項目も一覧に出てきます。

展開すると id・date・customer(Record)・items(List)の4列になります。

customer もRecordなので、同じように展開して code と name を取り出します。name のように意味があいまいな列名は、customer_name などに変えておくと後で混乱しません。

手順5:itemsのListをどう扱うか選ぶ

Listの列で展開ボタンを押すと、「新しい行に展開する」と「値の抽出」が表示されます。

新しい行に展開する

Listの要素ごとに行が分かれます。A001は2行になり、id・date・顧客の列は2行とも同じ値が繰り返されます。展開後の items 列にはRecordが入っているので、もう一度展開して sku と qty を取り出します。1明細1行の表にしたいときの方法です。

値の抽出

Listの中身を、区切り文字でつないで1つのセルにまとめます。中身が文字や数値だけのList(例:"tags": ["急ぎ", "再送"])なら、1注文1行のまま使えます。中身がRecordのListは、このままでは文字にできません。先に必要な項目を取り出す処理が必要です。

1注文1行の表にしたい場合は、items を展開せず、カスタム列で明細の件数だけ数えることもできます。

= List.Count([items])

明細の中身が必要なら、明細用のクエリを別に作ります。

行が増える箇所を確認する

行が増えるのは、Listを「新しい行に展開」したところだけです。展開の前と後で行数を確かめます。エディター下部のステータスバーに列数と行数が表示されます。

1注文1行の表の場合

行数と、id 列の重複しない値の数が一致するかを見ます。「表示」タブの「列のプロファイル」で個別の値の数を確認できます。既定では先頭1000行だけを対象に数えることがあるので、ステータスバーの「上位1000行に基づく列のプロファイル」をクリックし、データセット全体に切り替えて確認します。

1明細1行の表の場合

JSON内の明細数と行数が一致するかを確かめます。空のList("items": [])を持つ注文は、展開後に sku や qty がnullの行として残ることがあります。明細数と比べるときは、nullの行を除いて数えます。

2つ以上のListを同じ表で展開する場合

同じ表で2つのListを続けて「新しい行に展開」すると、組み合わせの数だけ行が増えます。たとえば明細2件とタグ3件の注文は6行になります。こうなる場合は、片方を「値の抽出」にするか、別のクエリに分けます。

nullの列が出たとき

nullは、原因によって対処が違います。

状況 考えられる原因 対処
一部の行だけnull その件に項目がない、または値がnull 元のJSONで該当する件を確認する。元からないなら空欄のままにするか、既定値に置き換える
列全体がnull 項目名の綴りや大文字・小文字が違う(id と ID)、または階層を間違えて展開した 展開ボタンに出る項目名を確認し直す。Power Queryの項目名は大文字と小文字を区別する
後ろの行にしかない項目が列にない 展開時の項目一覧が一部の行から作られた 展開ステップをやり直し、「さらに読み込む」で項目を追加する
明細の列がnullの行がある 空のListを展開した 1明細1行の表なら除外するか、「明細なし」として残すかを決める

データ型は最後に設定する

展開した直後の列は、型が決まっていない状態(列見出しのアイコンが「ABC123」)です。JSONの日付は文字列で入っていることが多いため、展開が終わってから日付や数値の列に型を設定します。

型の変換でエラーが出たら、元のデータの形式を確認します。2026-09-01 のような日付だけの形か、時刻やタイムゾーンが付いているかで、選ぶ型が変わります。

操作をMで見たときの形

ここまでの操作を詳細エディターで見ると、次のような形になります。画面で操作した場合、ステップ名は自動で付き、細かい書き方もこの例とは違うことがあります。

let
    ソース = Json.Document(File.Contents("C:\data\orders.json")),
    orders = ソース[orders],
    テーブル = Table.FromList(orders, Splitter.SplitByNothing(), {"Column1"}),
    注文展開 = Table.ExpandRecordColumn(テーブル, "Column1", {"id", "date", "customer", "items"}),
    顧客展開 = Table.ExpandRecordColumn(注文展開, "customer", {"code", "name"}, {"customer_code", "customer_name"}),
    明細行 = Table.ExpandListColumn(顧客展開, "items"),
    明細展開 = Table.ExpandRecordColumn(明細行, "items", {"sku", "qty"}),
    型設定 = Table.TransformColumnTypes(明細展開, {{"date", type date}, {"qty", Int64.Type}})
 in
    型設定

対応関係は次のとおりです。

  • Table.ExpandRecordColumn:Recordを列に展開する
  • Table.ExpandListColumn:Listを新しい行に展開する

行が増えるのは Table.ExpandListColumn のステップだけ、と覚えておくと、どこで行数が変わったか追いやすくなります。

日本語が文字化けする場合は、Json.Document(File.Contents("パス"), 65001) のように2つ目の引数で文字コード(65001はUTF-8)を指定してみてください。

仕上げのチェックリスト

  • 1行が何の1件か(注文か明細か)を決めた
  • 行数が、決めた単位の件数と一致する
  • Listを新しい行に展開したのは、必要な列だけになっている
  • 空のListから生まれたnullの行の扱いを決めた
  • 「さらに読み込む」で、後ろの行にしかない項目を確認した
  • 列名が重複しておらず、意味が分かる
  • 日付・数値の列に型を設定し、変換エラーがない
おすすめの記事