こんにちは、かつコーチです。
ここまでの記事では、すでにあるデータを取得するSELECT文を中心に解説してきました。
ここからは、データそのものを操作するDML(データ操作言語)に入っていきます。
第一弾は、テーブルに新しいデータを追加するINSERT文です。
読み終わる頃には、1件ずつの追加から複数件をまとめて追加する方法まで、実務でよく使う書き方が身につきます。
INSERT文とは?
テーブルに新しい行を追加するSQL文
INSERT文とは、テーブルに新しい行(レコード)を追加するためのSQL文です。
これまで扱ってきたSELECT文が「データ問い合わせ言語(DQL)」に分類されるのに対し、INSERT・UPDATE・DELETEはDML(Data Manipulation Language、データ操作言語)と呼ばれるグループに分類されます。
DQLがデータを「読む」ための文法なら、DMLはデータを「書き換える」ための文法だとイメージすると理解しやすいです。
なぜINSERT文が必要なのか
会員登録フォームから送信されたユーザー情報をデータベースに保存したり、注文が確定した瞬間に注文データを記録したりと、Webアプリの裏側では常にINSERT文が動いています。
CREATE TABLEでテーブルの器を作っただけでは、データベースは空っぽのままです。
INSERT文を使って初めて、テーブルは実際に使えるデータの集まりになります。
基本の書き方
この記事では、以下のテーブルを使います。
CREATE TABLE customers (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
prefecture VARCHAR(20),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
手順1:列名を指定して1件追加する
もっとも基本的な書き方は、列名と値をセットで指定する方法です。
INSERT INTO customers (name, email, prefecture)
VALUES ('田中太郎', 'tanaka@example.com', '東京都');
id列はAUTO_INCREMENTが設定されているため自動採番され、created_at列はDEFAULTで現在時刻が自動的に入るため、指定を省略できます。
手順2:複数件をまとめて追加する
INSERT文は、カンマ区切りで複数の値の組を並べることで、一度に複数件のデータを追加できます。
INSERT INTO customers (name, email, prefecture) VALUES
('佐藤花子', 'sato@example.com', '大阪府'),
('鈴木一郎', 'suzuki@example.com', '東京都'),
('高橋みどり', 'takahashi@example.com', '福岡県');
1件ずつINSERT文を実行するより、まとめて1回のINSERT文で実行する方がデータベースへの通信回数が減り、処理も速くなります。
大量データを投入するバッチ処理などでは、この書き方が基本になります。
手順3:列名を省略して追加する
列名を省略し、テーブル定義の順番通りにすべての値を指定する書き方もあります。
INSERT INTO customers VALUES (NULL, '伊藤健', 'ito@example.com', '愛知県', NOW());
idにNULLを指定するとAUTO_INCREMENTが働き、自動採番されます。
ただしこの書き方はテーブルの列構成が変わったときに動かなくなるリスクが高いため、次の「つまずきやすい設定・注意点」で詳しく説明します。
よくあるつまずきポイント・エラー対処
列名を省略した書き方でエラーになる
❌ Before:列名を省略した書き方に頼り、テーブル構成の変更に気づかず動かなくなる
-- prefecture列を追加する前に書いていたINSERT文
INSERT INTO customers VALUES (NULL, '渡辺誠', 'watanabe@example.com', NOW());
このINSERT文は、後からprefecture列を追加したことで列数が合わなくなり、ERROR 1136: Column count doesn't match value count at row 1というエラーになります。
私が実際にこのエラーに遭遇したのは、既存の会員登録処理にprefecture列を追加した後、古いバッチスクリプトの一部だけ修正し忘れていたときでした。
エラーメッセージだけを見ると原因が分かりにくく、「どのINSERT文が古いままなのか」を1つずつ確認する羽目になりました。
✅ After:列名を必ず明示して、テーブル構成の変更に強いコードにする
INSERT INTO customers (name, email, prefecture)
VALUES ('渡辺誠', 'watanabe@example.com', NULL);
列名を明示しておけば、テーブルに新しい列が追加されても既存のINSERT文はそのまま動き続けます。
「列名の省略は、書く量は減るがトラブルの原因になりやすい」と覚えておいてください。
NOT NULL制約違反でエラーになる
❌ Before:NOT NULL制約が付いている列の値を指定せずに追加しようとする
INSERT INTO customers (name, prefecture)
VALUES ('小林愛', '北海道');
email列にはNOT NULL制約が付いているため、値を指定しないとERROR 1364: Field 'email' doesn't have a default valueになります。
✅ After:NOT NULL制約が付いている列には必ず値を指定する
INSERT INTO customers (name, email, prefecture)
VALUES ('小林愛', 'kobayashi@example.com', '北海道');
エラーメッセージに列名がそのまま出力されるので、「どの列が必須なのか」をエラーメッセージから読み取る習慣をつけておくと、原因調査が速くなります。
応用・一歩先の使い方
SELECTの結果をそのまま別テーブルに追加する
INSERT文は、VALUESの代わりにSELECT文の結果を使って、既存データをまとめて別テーブルに追加することもできます。
INSERT INTO archived_customers (name, email, prefecture)
SELECT name, email, prefecture
FROM customers
WHERE created_at < '2025-01-01';
「古いデータをアーカイブ用テーブルに退避する」といった処理でよく使われる書き方です。
重複時の挙動を制御するON DUPLICATE KEY UPDATE
MySQLには、主キーや一意制約に重複があった場合の挙動を制御できるON DUPLICATE KEY UPDATEという構文があります。
INSERT INTO customers (id, name, email)
VALUES (1, '田中太郎', 'tanaka-new@example.com')
ON DUPLICATE KEY UPDATE email = VALUES(email);
「同じIDがすでに存在すればUPDATE、なければINSERT」という処理を1文で表現でき、これはMySQL独自の拡張構文です。
PostgreSQLではON CONFLICTという別の構文になるため、DB製品を移行する際は書き換えが必要になる点も覚えておいてください。
まとめ
この記事のポイント
- INSERT文はテーブルに新しい行を追加するDML(データ操作言語)の一つ
- 複数件をまとめて追加すると、1件ずつ実行するより効率的
- 列名は省略せず明示することで、テーブル構成の変更に強いコードになる
- NOT NULL制約のある列には必ず値を指定する
次に読むべき記事
データの追加ができたら、次は既存データを書き換える「UPDATE文でデータを更新する」に進んでください。
タグ: SQL, 初心者向け, DML