TL;DR
Power Queryがキーを検索したが何も見つからず、nullを返す代わりにエラーをスローしました。十中八九、原因はデータ型の不一致です。一方の列がtext型で、もう一方がnumber型やdate型になっています。マージまたはルックアップの手順の前に、両側を同じ型にキャストすればエラーは解消されます。
このエラーが発生する箇所
エラーは一か所だけでなく、複数の場所で表面化することがあります:
- Mコード内でTable.SelectRowsまたはRecord.Fieldを使った手動ルックアップ
- クエリのマージステップ後にネストされたテーブル列をドリルダウンする場合
- 行インデックスのルックアップパターン:
lookupTable{[ID = someValue]} - 特定の行をキーで参照するカスタムM関数
根本原因
Mの構文tableName{[ColumnName = value]}は、一致する行がちょうど1行あることを期待します。0行の場合はエラー、2行以上の場合もエラーになります。組み込みのフォールバック処理は存在しません。
厄介な点は、ルックアップが型に敏感であることです。文字列"123"と数値123はセル上では同じに見えますが、Power Queryにとっては全く異なるものです。この型の不一致は静かにマッチを失敗させます。その他のよくある原因:
- ソースデータが更新され、以前は有効だったキーが削除またはリネームされた
- 一方の列に先頭または末尾の空白が含まれている(CSVインポートでよく見られる)
- テキストとして保存された日付(
"2024-01-15")と実際のdate型の値 - Mコード内の列名のタイポ — 列名は大文字・小文字を区別する
修正1:両側のデータ型を一致させる
詳細エディターを開いてルックアップの行を見つけます。比較の前に両側を同じ型に強制変換します:
// 修正前 — 一方のテーブルでIDが数値、もう一方でテキストの場合に失敗する
let
result = lookupTable{[ID = sourceID]}[Value]
in
result
// 修正後 — すべてをまずテキストにキャストする
let
safeID = Text.From(sourceID),
safeTable = Table.TransformColumnTypes(lookupTable, {{"ID", type text}}),
result = safeTable{[ID = safeID]}[Value]
in
result
キーが常に数値(注文IDや従業員番号など)の場合は、代わりに数値にキャストします:
let
numID = Number.From(sourceID),
numTable = Table.TransformColumnTypes(lookupTable, {{"ID", type number}}),
result = numTable{[ID = numID]}[Value]
in
result
修正2:try…otherwise を使って存在しないキーを適切に処理する
すべてのソース行が一致するとは限りません — 実際のデータでは普通のことです。クエリをクラッシュさせる代わりに、ルックアップをtryでラップします:
let
safeLookup = try lookupTable{[ID = sourceID]}[Value] otherwise null
in
safeLookup
キーが存在しない場合はエラーではなくnullが返されます。ExcelのIFERROR関数でラップするのと同じ考え方です。データを読み込んだ後、nullの行をフィルタリングして、どのキーが一致しなかったかを確認できます。
修正3:比較前に空白をトリムする
CSVのエクスポートやコピー&ペーストしたデータには、目に見えないスペースが含まれていることで有名です。"ABC "と"ABC"は同じキーではありません。両側をトリムします:
let
cleanSource = Table.TransformColumns(sourceTable, {{"ID", Text.Trim}}),
cleanLookup = Table.TransformColumns(lookupTable, {{"ID", Text.Trim}}),
merged = Table.NestedJoin(
cleanSource, "ID",
cleanLookup, "ID",
"LookupResult", JoinKind.LeftOuter
)
in
merged
修正4:ルックアップの前にキーの存在を検証する
キーパラメーターを受け取るカスタム関数内では、前提とするのではなく先に存在確認を行います:
(inputID as text) =>
let
matches = Table.SelectRows(lookupTable, each [ID] = inputID),
result = if Table.RowCount(matches) > 0
then matches{0}[Value]
else "KEY NOT FOUND"
in
result
Table.SelectRowsは何も一致しない場合に空のテーブルを返します — エラーはスローされません。行インデックス構文{[ID = ...]}にはこの安全策がないため、ユーザー向けのクエリにはこのパターンの方が堅牢です。
修正5:UIでマージの結合タイプを確認する
クエリのマージダイアログを使用していて、マージされた列を展開したときにのみエラーが表示される場合、結合タイプが間違っている可能性があります:
- 適用したステップでマージステップをクリックする
- 結合の種類の設定を確認する — *内部結合(Inner Join)*は一致しない行を静かに削除するため、すべての行が存在することを前提とした後続のステップが壊れる
- **左外部結合(Left Outer Join)**に切り替えて、すべてのソース行を保持する(一致しない行のルックアップ列はnullになる)
- 必要に応じて、除外するためにnullを後でフィルタリングする
確認手順
修正を適用した後、以下を実行してください:
- Power Query エディターでプレビューの更新をクリックする — 赤いエラーバナーが消えているはず
- キー列の横にある型アイコンを確認する — 両方ともABC(テキスト)または123(数値)と表示されており、混在していないこと
- クイック診断ステップを追加する:
= Table.RowCount(lookupTable)でテーブルに行が読み込まれているか確認する(ゼロ行は多くある落とし穴) - 閉じて読み込み、出力行数が期待値と一致するか比較する
try...otherwise nullを使用した場合、結果列にフィルターを追加してnull行を抽出する — それらが調査すべき不一致キー
クイック診断チェックリスト
- [ ] キー比較の両側で同じデータ型になっているか?
- [ ] キー値に先頭または末尾のスペースが潜んでいないか?
- [ ] クエリが最初に作成された後にソースデータが変更されたか?
- [ ] ルックアップテーブルがゼロ行を読み込んでいないか?
- [ ] 本当は左外部結合が必要なのに内部結合を使用していないか?
- [ ] Mコードでキー列名のスペルと大文字・小文字が正しいか?

