こんにちは、とめです。
データ分析を独学で学び、未経験からデータアナリストへ転職し、今では本業をやりながら、副業でも活動しています!

SQLでデータ分析をしても「NULLが混ざってる」「同じデータが重複してる」「数値がおかしい」そんなデータばかりで、正直どこから手をつければいいか分からない…。

それ、よくある悩みだよ。
実はそれはスキル不足じゃなくて、データクリーニングのやり方を知らないだけなんだ。
データ分析は、どれだけ高度なSQLやロジックを使っても、元となるデータが汚れていれば、正しい結果は得られません。だからこそ、分析前の「下ごしらえ」であるデータクリーニングが重要になります。
とはいえ、
- 「データクリーニングって難しそう」
- 「どうやればいいの?」
と感じている方も多いはずです。
本記事では、データ抽出はできるけれど、分析前に何をどう整えればいいのか分からない人向けに、
データクリーニングのやり方をSQLで手順通りに解説します。
- データクリーニングで最初にやるべきこと
- NULLや重複データの正しい確認方法
- 表記ゆれ・データ型・異常値をSQLで整える方法
すべてMySQLでそのまま実行できるサンプルデータ付きなので、手を動かしながら理解できます。

データ分析の精度を一段引き上げたい方は、ぜひ最後まで読み進めてみてください!
データクリーニングとは?SQL視点でやさしく解説

データクリーニングは、分析を始める前に必ず行う「下ごしらえ」です。
どれだけ高度な分析手法やロジックを使っても、元となるデータが汚れていれば、分析結果は信用できません。
なぜなら、データ分析は「入力されたデータ」をそのまま材料として扱うからです。
入力がズレていれば、出てくる答えも当然ズレてしまいます。

ここで、料理にたとえて考えてみましょう。
- 食材が傷んでいる
- 皮やゴミがついたまま
- 分量がバラバラ
この状態で料理をしても、美味しい料理は作れませんよね。
データ分析もまったく同じ構造です。

分析手法ばかり勉強してたけど、そもそもデータが汚かったら意味ないってことなんだね…

そう。分析の質は、データクリーニングの質でほぼ決まると言ってもいいよ!
つまり、
「まずはデータを使える状態に整えること」=データクリーニングです。
特に実務では、
- NULLが混ざっている
- 同じデータが重複している
- 表記や形式がバラバラ
といった状態は日常茶飯事です。
分析に入る前に、どこまで整えるかを判断し、最低限の修正を行うことが重要になります。

分析の前の“土台づくり”を、疎かにせずに、データクリーニングを理解していこう!
SQLでデータクリーニングを行う基本的な流れ

SQLでデータクリーニングをする手順は以下です。
- データの中身を把握する
- 欠損値(NULL)を確認する
- 重複データを見つけて整理する
- 表記ゆれをSQLで統一する
- データ型の不整合を修正する
- 異常値を検出する
- 分析用データとして整形する

1つずつ確認して実際にやってみよう!
※ここからは、SQLでのデータクリーニングのやり方を、実際に手を動かしながら理解できるように、サンプルデータを用意して解説します。
すべてのSQLは、MySQLでそのまま実行可能なので、手元の環境で一緒に試してみてください。
サンプルデータを作成する

では実際にデータクリーニングする前に、サンプルデータを作成してみよう!
CREATE TABLE users (
id INT,
name VARCHAR(50),
age VARCHAR(10),
email VARCHAR(100)
);
- 上記のSQL構文をコピーして貼り付け
- 実行する

次にわざと以下の「汚れたデータ」を入れていきます!
INSERT INTO users (id, name, age, email) VALUES
(1, 'Taro', '25', 'taro@example.com'),
(2, 'Hanako', '30', 'hanako@example.com'),
(2, 'Hanako', '30', 'hanako@example.com'), -- 重複
(3, ' Jiro ', 'twenty', 'JIRO@EXAMPLE.COM'), -- 表記ゆれ・型不整合
(4, NULL, '40', 'shiro@example.com'), -- NULL
(5, 'Goro', '200', 'goro@example.com'); -- 異常値

あえて“汚いデータ”を作るのが、データクリーニング理解の近道だよ!
手順①:データの中身を把握する
データクリーニングで、最初にやるべきことは、データの「全体像」を把握することです。
いきなり修正や加工を始めるのではなく、まずはどんなデータが入っているのかを確認することが重要になります。
なぜなら、データの構造や状態を知らないままSQLを書くと、
- 想定と違う列名を使ってエラーになる
- 不要な処理をしてしまう
- 条件ミスでデータを壊してしまう
といったトラブルにつながりやすいからです。

安全にデータクリーニングを進めるための第一歩が「確認」です。
まずは、テーブルの中身をそのまま見てみましょう。
SELECT * FROM users;

以下のように表示されればOKです!
mysql> SELECT * FROM users;
+------+--------+--------+--------------------+
| id | name | age | email |
+------+--------+--------+--------------------+
| 1 | Taro | 25 | taro@example.com |
| 2 | Hanako | 30 | hanako@example.com |
| 2 | Hanako | 30 | hanako@example.com |
| 3 | Jiro | twenty | JIRO@EXAMPLE.COM |
| 4 | NULL | 40 | shiro@example.com |
| 5 | Goro | 200 | goro@example.com |
+------+--------+--------+--------------------+
6 rows in set (0.00 sec)
このSQLは、usersテーブルに入っているデータを一覧で表示するだけなので、データを変更することは一切ありません。
次に、データが全部で何件あるのかを確認します。
SELECT COUNT(*) FROM users;

以下のように表示されればOKです!
mysql> SELECT COUNT(*) FROM users;
+----------+
| COUNT(*) |
+----------+
| 6 |
+----------+
1 row in set (0.01 sec)
件数を把握しておくことで、
- データ量が多いのか少ないのか
- 後続の処理が重そうかどうか
といった判断ができるようになります。
データクリーニングのやり方は、まず「中身を見る」「件数を知る」ことから始めるのが鉄則です。
この一手間を挟むだけで、その後の作業を安全かつスムーズに進められます。
手順②:欠損値(NULL)を確認する
次にやるべきことは、データの中にNULL(欠損値)がどれくらい含まれているかを把握することです。
NULLの存在を無視したまま分析を進めると、集計結果がズレたり、想定外のエラーが発生したりします。
なぜなら、SQLではNULLが含まれると計算や集計の結果に影響が出るからです。
特に平均値・件数・割合などを扱う場合、NULLをどう扱うかで結果が大きく変わります。
そこでまずは、「どの列に」「どれくらいNULLがあるのか」を確認しましょう。
今回は、「name」カラムを例に確認します。
SELECT
COUNT(*) AS total,
COUNT(name) AS name_not_null
FROM users;
結果が以下になります。
mysql> SELECT
-> COUNT(*) AS total,
-> COUNT(name) AS name_not_null
-> FROM users;
+-------+---------------+
| total | name_not_null |
+-------+---------------+
| 6 | 5 |
+-------+---------------+
1 row in set (0.00 sec)
このSQLのポイントは以下の通りです。
COUNT(*)
→ テーブル全体の件数をカウントCOUNT(name)
→ NULL以外のnameだけをカウント
この2つを比べることで、
nameにNULLが含まれているかどうかが一目で分かります。

NULL確認は、COUNT(列名)を使うのが、一番シンプルだよ!
ここで大切なのは、まだNULLを消したり埋めたりしないことです。
このSTEPの目的はあくまで「現状把握」。
NULLがある事実と、その量を正しく認識することがゴールになります。
データクリーニングのやり方では、NULLを処理する前に「どこに・どれだけあるか」をSQLで必ず確認しましょう。
手順③:重複データを確認する
次に確認すべきは、同じデータが重複して登録されていないかどうかです。
重複データをそのままにして分析を行うと、件数や平均値が実態よりも大きく算出され、分析結果が大きく歪んでしまいます。
なぜなら、SQLはデータを「そのままの行数」で集計するため、1人のユーザーが2回カウントされていれば、2人分として扱われてしまうからです。
特にユーザー数・売上件数・申込数などを扱う場合、重複は致命的なミスにつながります。
そこで、まずは「本来ユニークであるべき列」に重複がないかを確認します。

今回のサンプルデータでは、「id」がユーザーを一意に識別する列だと仮定します。
SELECT id, COUNT(*)
FROM users
GROUP BY id
HAVING COUNT(*) > 1;
以下のように、表示されていればOKです。
mysql> SELECT id, COUNT(*)
-> FROM users
-> GROUP BY id
-> HAVING COUNT(*) > 1;
+------+----------+
| id | COUNT(*) |
+------+----------+
| 2 | 2 |
+------+----------+
1 row in set (0.01 sec)
このSQLで行っていることは、次の通りです。
GROUP BY id
→ idごとにデータをまとめるCOUNT(*)
→ 各idが何回出現しているかを数えるHAVING COUNT(*) > 1
→ 2回以上出現しているid(=重複)だけを抽出
これにより、重複して登録されているデータをピンポイントで特定できます。

GROUP BYとHAVINGって、こういう時に使うんだね!

WHEREは行の条件、HAVINGは集計後の条件って覚えると分かりやすいよ
手順③の目的は、「どの列で、どんな重複が起きているか」を把握することです。
データクリーニングのやり方では、集計や分析に入る前に、必ず重複データの有無をSQLで確認しましょう。
手順④:表記ゆれをSQLで統一する
次に行う手順④では、表記ゆれを統一する作業です。
表記ゆれは、分析前にSQLで必ず統一しておくべきです。
表記がバラバラなままでは、同じデータを正しく集計・分析することができません。
なぜなら、SQLは文字列を「完全一致」で判定するため、
人間にとっては同じに見える値でも、コンピュータ上では別物として扱われてしまうからです。
例えば、今回のサンプルデータには次のような表記ゆれがあります。
' Jiro 'のように前後に余分な空白が入っている'JIRO@EXAMPLE.COM'のように大文字・小文字が混在している
この状態で集計すると、
同一人物なのに別人としてカウントされる可能性があります。
そこで使うのが、表記ゆれを統一するSQLの文字列関数です。
SELECT
TRIM(name) AS name,
LOWER(email) AS email
FROM users;

上記のSQL構文を入力して、以下のように表示されればOKです!
mysql> SELECT
-> TRIM(name) AS name,
-> LOWER(email) AS email
-> FROM users;
+--------+--------------------+
| name | email |
+--------+--------------------+
| Taro | taro@example.com |
| Hanako | hanako@example.com |
| Hanako | hanako@example.com |
| Jiro | jiro@example.com |
| NULL | shiro@example.com |
| Goro | goro@example.com |
+--------+--------------------+
6 rows in set (0.01 sec)
このSQLでは、次の2つの処理を行っています。
TRIM(name)
→ 文字列の前後の空白を削除するLOWER(email)
→ 英字をすべて小文字に変換する
これだけで、表記ゆれの多くは解消できます。

見た目は同じでも、SQLだと別扱いなんだね…

表記ゆれは“人間の感覚”と“SQLの判定”のズレから生まれるから、必ず統一するようにしよう!
まずは「どう整形すれば統一できるか」を確認しましょう。
データクリーニングのやり方では、表記ゆれをSQL関数で揃えることで、分析の精度を大きく高められます。
手順⑤:データ型の不整合を修正する
続いて手順⑤で行う作業は、データ型の不整合を修正します。
分析に使う前に、データ型は必ず正しい型へそろえる必要があります。
見た目は問題なさそうでも、データ型が合っていないと、集計や計算が正しく行えません。
なぜなら、SQLでは、数値として扱うデータと、文字列として扱うデータはまったく別物だからです。
特に数値計算(平均・合計・大小比較など)は、型が不正だとエラーや誤集計の原因になります。
今回のサンプルデータでは、「age」カラムがVARCHAR型として定義されています。
そのため、
'25'や'30'のような数値文字列'twenty'のような数値ではない文字列
が混在しています。

そこで、手順⑤では、数値として扱えるかどうかを確認するために、次のSQLを実行します。
SELECT
CAST(age AS SIGNED) AS age
FROM users;

実行すると以下のSQLが表示されます。
mysql> SELECT
-> CAST(age AS SIGNED) AS age
-> FROM users;
+------+
| age |
+------+
| 25 |
| 30 |
| 30 |
| 0 |
| 40 |
| 200 |
+------+
6 rows in set, 1 warning (0.01 sec)
このSQLのポイントは以下の通りです。
CAST(age AS SIGNED)
→ 文字列を数値型(整数)に変換する- 数値に変換できない値は、
0 もしくは「NULL」相当として扱われる(DB仕様による)

「twenty」みたいな値があると、ちゃんと数値にならないんだね…。

型の不整合は、見た目では気づきにくいから注意してね!
まずは「どのデータが数値として使えないか」を洗い出しましょう。
データクリーニングのやり方では、分析前に必ずデータ型を確認・修正し、SQLが正しく計算できる状態を作ることが重要です。
手順⑥:異常値を検出する
続いて行う作業は異常値を検出する作業です。
分析前には、明らかにおかしい数値(異常値)が含まれていないかを必ず確認します。
異常値をそのまま使ってしまうと、平均値や傾向が大きく歪み、分析結果の信頼性が著しく下がるからです。
なぜなら、SQLは「値が正しいかどうか」を判断せず、入っている数値をそのまま計算に使ってしまうからです。
特に年齢・金額・回数などの数値データでは、異常値の影響が非常に大きくなります。
今回のサンプルデータでは、「age」に現実的とは言えない値が含まれています。

そこで、次のSQLを使って異常値を抽出します!
SELECT *
FROM users
WHERE CAST(age AS SIGNED) > 120;

実行すると、以下のように結果が出ます。
mysql> SELECT *
-> FROM users
-> WHERE CAST(age AS SIGNED) > 120;
+------+------+------+------------------+
| id | name | age | email |
+------+------+------+------------------+
| 5 | Goro | 200 | goro@example.com |
+------+------+------+------------------+
1 row in set, 1 warning (0.00 sec)
このSQLでは、
CAST(age AS SIGNED)で数値として扱えるようにしたうえで- 120歳を超えるデータだけを抽出
をしています。

これを使うことで、異常な数値をSQLでも判断できるんだね!

そう!異常値は“感覚”じゃなく“条件”で切り分けるようにしていこう!
まずは「どんな異常値が、どれくらい含まれているか」を把握しましょう。
データクリーニングのやり方では、分析前に異常値を検出し、影響の大きいデータを事前に洗い出すことが欠かせません。
STEP⑦ 分析用データとして整形する
最後に行うべきは、分析に使いやすい形へデータを整形することです。
これまで確認・調整してきた内容を踏まえ、「分析にそのまま使える最終形」を作ります。
なぜこのSTEPが重要かというと、NULL・重複・表記ゆれ・型の不整合が残ったままでは、どれだけ分析手法が正しくても、結果の信頼性が担保できないからです。

分析は「きれいに整ったデータ」があって初めて意味を持つからね!
そこで、これまでのSTEPをまとめて反映したSQLがこちらです。
SELECT DISTINCT
id,
TRIM(name) AS name,
CAST(age AS SIGNED) AS age,
LOWER(email) AS email
FROM users
WHERE name IS NOT NULL;

実行すると、以下のように結果が出ます。
mysql> SELECT DISTINCT
-> id,
-> TRIM(name) AS name,
-> CAST(age AS SIGNED) AS age,
-> LOWER(email) AS email
-> FROM users
-> WHERE name IS NOT NULL;
+------+--------+------+--------------------+
| id | name | age | email |
+------+--------+------+--------------------+
| 1 | Taro | 25 | taro@example.com |
| 2 | Hanako | 30 | hanako@example.com |
| 3 | Jiro | 0 | jiro@example.com |
| 5 | Goro | 200 | goro@example.com |
+------+--------+------+--------------------+
4 rows in set, 1 warning (0.00 sec)
このSQLでは、次のような整形を同時に行っています。
DISTINCT
→ 重複データを除外TRIM(name)
→ 名前の前後の空白を削除CAST(age AS SIGNED)
→ 年齢を数値として扱えるように変換LOWER(email)
→ メールアドレスの表記を小文字に統一WHERE name IS NOT NULL
→ 分析に使えないデータを除外

今までのSTEPが、ここで全部つながる感じだね!

そう。データクリーニングは“1つずつ整えて、最後にまとめる”のがコツだよ!
「SELECT」文だけで整形することで、安全に分析用データを作成できます。
データクリーニングのやり方では、最終的に「分析に使える形」までSQLで整形してから、次の分析工程へ進みましょう。
まとめ|SQLでできるデータクリーニングの考え方

データクリーニングは、データ分析に入る前に必ず行う「下ごしらえ」です。
どれだけ高度な分析手法やロジックを使っても、元となるデータが汚れていれば、分析結果は信用できません。
本記事では、SQLだけで実践できるデータクリーニングのやり方を、実務の流れに沿って解説しました。
- データの中身を把握する
- 欠損値(NULL)を確認する
- 重複データを見つけて整理する
- 表記ゆれをSQLで統一する
- データ型の不整合を修正する
- 異常値を検出する
- 分析用データとして整形する
というステップで進めてきました。
ここで大切なのは、完璧にきれいなデータを作ることではありません。
あくまでゴールは、「分析に使える状態」に整えることです。
SQLでデータクリーニングができるようになると、
- 分析結果の精度が上がる
- 前処理の手戻りや修正作業が減る
- 実務で「データが分かる人」として信頼されやすくなる
といった大きなメリットがあります。

まずは、今回紹介したSQLを使って、手元のデータを一度クリーニングしてみてください。
以上、とめでした!




コメント