ゴールのイメージをそろえる
今回のテーマは「Power Query で テーブル全体を見て“完全に同じ行”を重複として削除する実務テンプレ」です。
ここでいう「重複行削除(全列)」は、
「1行まるごと、すべての列の値が同じ行は、1件だけ残して他は消す」
という意味です。
「キー列だけで重複判定」ではなく、「全列一致で重複判定」するパターンなので、
“インポートした生データから、まるっと同じ行を落としたい”ときに使います。
まず「どんな重複」を消したいのかを具体化する
例題データをイメージする
次のようなテーブルを想像してください。
| 受注番号 | 顧客コード | 商品コード | 数量 | 金額 |
|---|---|---|---|---|
| 1001 | C001 | A001 | 10 | 1200 |
| 1001 | C001 | A001 | 10 | 1200 |
| 1002 | C002 | A002 | 5 | 800 |
| 1003 | C003 | A003 | 3 | 600 |
| 1003 | C003 | A003 | 3 | 600 |
ここで「完全に同じ行」が2つずつあります。
1行目と2行目は、全列の値が完全一致。
4行目と5行目も、全列の値が完全一致。
やりたいことは、
「1001 の行は 1件だけ残す」
「1003 の行も 1件だけ残す」
つまり、「全列が同じ行は 1件だけ残して、残りを削除する」ということです。
基本テンプレ:Table.Distinct で「全列重複」を削除する
もっともシンプルな書き方
Power Query には、重複行を削除するための Table.Distinct という関数があります。
「全列で重複判定したい」場合は、列指定を省略すれば OK です。
let
Source = ・・・前のステップ・・・,
RemovedDuplicates =
Table.Distinct(Source)
in
RemovedDuplicates
Power Queryこれだけで、「テーブル全体を見て、完全に同じ行は 1件だけ残す」という動きになります。
先ほどの例なら、結果はこうなります。
| 受注番号 | 顧客コード | 商品コード | 数量 | 金額 |
|---|---|---|---|---|
| 1001 | C001 | A001 | 10 | 1200 |
| 1002 | C002 | A002 | 5 | 800 |
| 1003 | C003 | A003 | 3 | 600 |
「どの行を残すか」は、元の順番に依存します。
同じ内容の行が複数あっても、最初に出てきた行が残り、後ろの分が削除されます。
重要ポイント1:「全列一致」であることが前提になる
1つでも違う列があれば「別の行」とみなされる
Table.Distinct(Source) は、「全列の値がすべて同じかどうか」で重複判定します。
つまり、1列でも違えば「別の行」として残ります。
例えば、次の2行はどうでしょう。
| 受注番号 | 顧客コード | 商品コード | 数量 | 金額 |
|---|---|---|---|---|
| 1001 | C001 | A001 | 10 | 1200 |
| 1001 | C001 | A001 | 10 | 1200.0 |
見た目は同じでも、型や値が微妙に違うと「別物」として扱われることがあります。
また、次のようなパターンも同様です。
“1200”(文字列)と 1200(数値)
” C001″(前にスペースあり)と “C001”
“2024/01/01″(文字列)と #date(2024,1,1)(日付型)
「全列一致で重複判定する」前に、
型変換・トリム・カンマ削除・日付変換などのクレンジングを済ませておくと、
“意図した通りの重複削除”になりやすくなります。
重要ポイント2:「どの行を残すか」をコントロールしたい場合
先にソートしてから Table.Distinct する
Table.Distinct は、「最初に出てきた行を残し、後ろの重複を削除する」という動きをします。
ということは、「どの行を残したいか」をコントロールしたければ、
先にソートしておけばいい、ということです。
例えば、次のようなケースを考えます。
同じ内容の行が複数あるが、「更新日時が一番新しい行だけ残したい」。
この場合は、
更新日時で降順ソートする(新しいものが上に来るように)。
そのあとで Table.Distinct する。
という順番にします。
let
Source = ・・・前のステップ・・・,
Sorted =
Table.Sort(
Source,
{{"更新日時", Order.Descending}}
),
RemovedDuplicates =
Table.Distinct(Sorted)
in
RemovedDuplicates
Power Queryこうすると、「同じ内容の行が複数ある場合は、更新日時が一番新しい行だけが残る」という動きになります。
“どの行を残すか”を意識できているかどうかで、実務の精度がかなり変わります。
重要ポイント3:NULL や空白も「値の一部」として判定される
NULL を含む行の重複判定
Table.Distinct は、NULL も「値の一つ」として扱います。
つまり、次の2行は「完全に同じ」とみなされます。
| 受注番号 | 顧客コード | 商品コード | 数量 | 金額 |
|---|---|---|---|---|
| 1001 | C001 | null | 10 | 1200 |
| 1001 | C001 | null | 10 | 1200 |
一方、次の2行は「別の行」です。
| 受注番号 | 顧客コード | 商品コード | 数量 | 金額 |
|---|---|---|---|---|
| 1001 | C001 | “” | 10 | 1200 |
| 1001 | C001 | null | 10 | 1200 |
空文字(””)と NULL は別物だからです。
「空文字は全部 NULL に統一してから重複判定したい」
「NULL は残したくないので、先に除外してから重複削除したい」
など、NULL や空白の扱いを先に決めておくと、
“想定外に重複が残る/消える”という事故を防げます。
実務テンプレとしての流れをまとめる
クレンジングと重複削除の組み合わせ
実務で「全列重複削除」を使うときは、だいたい次の流れが安定します。
1つ目のステップで、型変換(数値・日付・テキスト)をそろえる。
2つ目のステップで、トリム・全角→半角・改行削除・不正文字除去などを行う。
3つ目のステップで、必要ならソート(残したい行を上に持ってくる)。
4つ目のステップで、Table.Distinct による「全列重複削除」。
この順番にしておくと、
見た目は同じなのに空白や全角の違いで重複判定がズレる
残したい行ではない方が残ってしまう
といった“よくあるハマり”をかなり避けられます。
実務テンプレとしてのまとめ
「重複行削除(全列)」の本質は、とてもシンプルです。
Table.Distinct(Source) で、「全列の値が完全一致する行は 1件だけ残す」。
残したい行をコントロールしたければ、先にソートしてから Table.Distinct する。
そして、より重要なのはその前段階——
型変換・トリム・NULL/空白の統一などのクレンジングを済ませてから重複削除する、という“順番の設計”です。
ここまでの前処理テンプレ(トリム、全角→半角、改行削除、不正文字除去、日付・数値変換)と、
今回の「全列重複削除」を組み合わせると、
かなり“信頼できるユニークな明細テーブル”を作れるようになります。
