「テーブルは作れたけど、どうやってデータを入れるの?」
そんな疑問を持った方に向けて、今回はMySQLでデータを追加する命令である「INSERT文」の使い方を解説します。
INSERT
は、MySQLを使う上で必ず必要になる基本操作の一つです。
この記事では、初心者の方でもすぐ実践できるように、文法の基礎から応用、よくあるエラーの対処法までを丁寧にご紹介します。
基本のINSERT文の書き方

最もシンプルな構文
INSERT INTO テーブル名 (カラム1, カラム2, カラム3) VALUES (値1, 値2, 値3);
実際の例で理解しよう
usersテーブルの構造
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE,
age INT
);
1件のデータを追加
INSERT INTO users (name, email, age) VALUES ('田中太郎', 'tanaka@example.com', 25);
この例では:
users
:データを追加するテーブル名(name, email, age)
:データを入れるカラムを指定VALUES ('田中太郎', 'tanaka@example.com', 25)
:それぞれのカラムに入れる値
実行前後のテーブルの状態
実行前
id | name | age | |
---|---|---|---|
(空のテーブル) |
実行後
id | name | age | |
---|---|---|---|
1 | 田中太郎 | tanaka@example.com | 25 |
重要なルール
カラム名と値の数は必ず一致
-- ❌ 間違い:カラム3つ、値2つ
INSERT INTO users (name, email, age) VALUES ('田中太郎', 'tanaka@example.com');
-- ✅ 正しい:カラム3つ、値3つ
INSERT INTO users (name, email, age) VALUES ('田中太郎', 'tanaka@example.com', 25);
文字列はシングルクォートで囲む
-- ✅ 正しい
INSERT INTO users (name, email) VALUES ('田中太郎', 'tanaka@example.com');
-- ❌ 間違い
INSERT INTO users (name, email) VALUES (田中太郎, tanaka@example.com);
数値はクォート不要
-- ✅ 正しい
INSERT INTO users (age) VALUES (25);
-- ⚠️ 動作するが推奨しない
INSERT INTO users (age) VALUES ('25');
カラムの指定方法とパターン

全てのカラムを指定する場合
INSERT INTO users (name, email, age) VALUES ('佐藤花子', 'sato@example.com', 30);
一部のカラムだけを指定する場合
-- 年齢を省略(NULLまたはデフォルト値が入る)
INSERT INTO users (name, email) VALUES ('山田次郎', 'yamada@example.com');
カラム名を省略する場合(非推奨)
-- テーブルの全カラムを順番通りに指定
INSERT INTO users VALUES (NULL, '鈴木一郎', 'suzuki@example.com', 28);
なぜ非推奨?
- テーブル構造が変わるとエラーになる
- 何の値を入れているかわかりにくい
- メンテナンス性が悪い
複数行のINSERTで効率アップ
基本的な複数行INSERT
INSERT INTO users (name, email, age)
VALUES
('佐藤花子', 'sato@example.com', 30),
('鈴木次郎', 'suzuki@example.com', 28),
('高橋三郎', 'takahashi@example.com', 35);
実行結果
id | name | age | |
---|---|---|---|
1 | 田中太郎 | tanaka@example.com | 25 |
2 | 佐藤花子 | sato@example.com | 30 |
3 | 鈴木次郎 | suzuki@example.com | 28 |
4 | 高橋三郎 | takahashi@example.com | 35 |
複数行INSERTのメリット
パフォーマンスが向上
- 1回のSQL実行で複数行を処理
- データベースへの接続回数が減る
- トランザクションの回数が減る
コードが簡潔
- 何度もINSERT文を書く必要がない
- エラーハンドリングが楽
実際の処理時間比較例
-- 遅い方法:1件ずつ3回実行
INSERT INTO users (name, email) VALUES ('ユーザー1', 'user1@example.com');
INSERT INTO users (name, email) VALUES ('ユーザー2', 'user2@example.com');
INSERT INTO users (name, email) VALUES ('ユーザー3', 'user3@example.com');
-- 速い方法:1回で3件実行
INSERT INTO users (name, email)
VALUES
('ユーザー1', 'user1@example.com'),
('ユーザー2', 'user2@example.com'),
('ユーザー3', 'user3@example.com');
AUTO_INCREMENTの扱い方
AUTO_INCREMENTとは
AUTO_INCREMENTは、自動で1、2、3…と番号を振る機能です。主にIDカラムで使われます。
AUTO_INCREMENTカラムは省略できる
-- idを省略(自動で番号が振られる)
INSERT INTO users (name, email, age) VALUES ('田中太郎', 'tanaka@example.com', 25);
明示的に値を指定することも可能
-- idを明示的に指定
INSERT INTO users (id, name, email, age) VALUES (100, '特別ユーザー', 'special@example.com', 40);
AUTO_INCREMENTの動作例
初期状態(空のテーブル)
INSERT INTO users (name, email) VALUES ('ユーザー1', 'user1@example.com');
-- → id = 1
INSERT INTO users (name, email) VALUES ('ユーザー2', 'user2@example.com');
-- → id = 2
INSERT INTO users (id, name, email) VALUES (10, 'ユーザー3', 'user3@example.com');
-- → id = 10(明示的に指定)
INSERT INTO users (name, email) VALUES ('ユーザー4', 'user4@example.com');
-- → id = 11(10の次から自動採番が再開)
さまざまなデータ型の入れ方
文字列データ
INSERT INTO users (name, email) VALUES ('田中太郎', 'tanaka@example.com');
数値データ
INSERT INTO products (name, price, stock) VALUES ('商品A', 1500, 100);
日付・時刻データ
INSERT INTO posts (title, content, created_at)
VALUES ('記事タイトル', '記事の内容です', '2025-06-03 14:30:00');
-- 現在時刻を入れる場合
INSERT INTO posts (title, content, created_at)
VALUES ('記事タイトル', '記事の内容です', NOW());
真偽値(BOOLEAN)データ
INSERT INTO users (name, email, is_active)
VALUES ('田中太郎', 'tanaka@example.com', TRUE);
-- 0と1でも指定可能
INSERT INTO users (name, email, is_active)
VALUES ('佐藤花子', 'sato@example.com', 1);
NULLデータ
-- ageにNULLを入れる
INSERT INTO users (name, email, age) VALUES ('山田次郎', 'yamada@example.com', NULL);
-- カラムを省略してもNULLになる(制約による)
INSERT INTO users (name, email) VALUES ('鈴木一郎', 'suzuki@example.com');
JSON データ(MySQL 5.7以降)
INSERT INTO user_settings (user_id, preferences)
VALUES (1, '{"theme": "dark", "language": "ja"}');
よくあるINSERTエラーと解決策
1. カラム数と値の数が合わない
エラー例
INSERT INTO users (name, email, age) VALUES ('田中太郎', 'tanaka@example.com');
エラーメッセージ
ERROR 1136 (21S01): Column count doesn't match value count at row 1
解決策
-- 全ての値を指定
INSERT INTO users (name, email, age) VALUES ('田中太郎', 'tanaka@example.com', 25);
-- または必要なカラムだけ指定
INSERT INTO users (name, email) VALUES ('田中太郎', 'tanaka@example.com');
2. 一意性制約違反(UNIQUE制約)
エラー例
-- 1回目は成功
INSERT INTO users (name, email) VALUES ('田中太郎', 'tanaka@example.com');
-- 2回目はエラー(同じメールアドレス)
INSERT INTO users (name, email) VALUES ('田中次郎', 'tanaka@example.com');
エラーメッセージ
ERROR 1062 (23000): Duplicate entry 'tanaka@example.com' for key 'email'
解決策
-- 違うメールアドレスを使用
INSERT INTO users (name, email) VALUES ('田中次郎', 'tanaka2@example.com');
-- または事前にチェック
SELECT * FROM users WHERE email = 'tanaka@example.com';
3. NOT NULL制約違反
エラー例
INSERT INTO users (email, age) VALUES ('test@example.com', 25);
-- nameカラムがNOT NULLの場合エラー
エラーメッセージ
ERROR 1364 (HY000): Field 'name' doesn't have a default value
解決策
-- 必須カラムに値を指定
INSERT INTO users (name, email, age) VALUES ('田中太郎', 'test@example.com', 25);
4. データ型不整合
エラー例
INSERT INTO users (name, email, age) VALUES ('田中太郎', 'tanaka@example.com', 'twenty-five');
-- age は INT型なのに文字列を指定
エラーメッセージ
ERROR 1366 (HY000): Incorrect integer value: 'twenty-five' for column 'age' at row 1
解決策
-- 適切なデータ型で指定
INSERT INTO users (name, email, age) VALUES ('田中太郎', 'tanaka@example.com', 25);
5. 存在しないカラム名
エラー例
INSERT INTO users (name, emial, age) VALUES ('田中太郎', 'tanaka@example.com', 25);
-- email を emial と誤記
エラーメッセージ
ERROR 1054 (42S22): Unknown column 'emial' in 'field list'
解決策
-- 正しいカラム名を使用
INSERT INTO users (name, email, age) VALUES ('田中太郎', 'tanaka@example.com', 25);
実際の業務でよく使うINSERTパターン

ユーザー登録
INSERT INTO users (username, email, password_hash, full_name, created_at)
VALUES
('tanaka123', 'tanaka@example.com', 'hashed_password_123', '田中太郎', NOW()),
('sato456', 'sato@example.com', 'hashed_password_456', '佐藤花子', NOW());
商品登録
INSERT INTO products (name, description, price, category_id, stock_quantity, is_active)
VALUES
('ノートパソコン', 'Windows 11搭載の高性能ノートPC', 89800, 1, 50, TRUE),
('ワイヤレスマウス', 'Bluetooth対応の軽量マウス', 2980, 2, 200, TRUE);
注文データの登録
INSERT INTO orders (customer_id, order_date, total_amount, status)
VALUES (123, NOW(), 92780, 'pending');
-- 注文明細も一緒に登録
INSERT INTO order_items (order_id, product_id, quantity, unit_price)
VALUES
(LAST_INSERT_ID(), 1, 1, 89800),
(LAST_INSERT_ID(), 2, 1, 2980);
ログデータの登録
INSERT INTO access_logs (user_id, action, ip_address, user_agent, timestamp)
VALUES (456, 'login', '192.168.1.100', 'Mozilla/5.0...', NOW());
設定データの登録
INSERT INTO user_settings (user_id, setting_key, setting_value)
VALUES
(123, 'theme', 'dark'),
(123, 'language', 'ja'),
(123, 'notification_email', 'true');
INSERT文の応用テクニック
INSERT … SELECT で他のテーブルからデータをコピー
基本的な使い方
INSERT INTO new_users (name, email)
SELECT name, email FROM old_users WHERE created_at >= '2025-01-01';
条件付きでのデータコピー
-- アクティブなユーザーのみをコピー
INSERT INTO active_users (user_id, name, email, last_login)
SELECT id, name, email, last_login_at
FROM users
WHERE is_active = TRUE AND last_login_at >= '2025-01-01';
集計結果を新しいテーブルに保存
INSERT INTO monthly_sales_summary (year_month, total_amount, order_count)
SELECT
DATE_FORMAT(order_date, '%Y-%m') as year_month,
SUM(total_amount) as total_amount,
COUNT(*) as order_count
FROM orders
WHERE order_date >= '2025-01-01'
GROUP BY DATE_FORMAT(order_date, '%Y-%m');
ON DUPLICATE KEY UPDATE で重複時の動作を制御
INSERT INTO user_stats (user_id, login_count, last_login)
VALUES (123, 1, NOW())
ON DUPLICATE KEY UPDATE
login_count = login_count + 1,
last_login = NOW();
この例では:
- user_id=123が初回の場合:新規レコード作成
- user_id=123が既存の場合:login_countを+1、last_loginを更新
REPLACE INTO による上書きINSERT
REPLACE INTO user_preferences (user_id, setting_name, setting_value)
VALUES (123, 'theme', 'light');
REPLACE INTO は:
- レコードが存在しない場合:INSERT
- レコードが存在する場合:DELETE してから INSERT
INSERT IGNORE でエラーを無視
INSERT IGNORE INTO users (name, email)
VALUES
('田中太郎', 'tanaka@example.com'),
('佐藤花子', 'duplicate@example.com'), -- 重複エラーでも処理続行
('山田次郎', 'yamada@example.com');
パフォーマンスを考慮した INSERT

大量データのINSERT
一括INSERT の最適化
-- 1000件程度ずつに分けて実行
INSERT INTO large_table (col1, col2, col3)
VALUES
('data1', 'value1', 123),
('data2', 'value2', 456),
-- ... 1000件程度
('data1000', 'value1000', 789);
トランザクションを使用
START TRANSACTION;
INSERT INTO products (name, price) VALUES ('商品1', 100);
INSERT INTO products (name, price) VALUES ('商品2', 200);
INSERT INTO products (name, price) VALUES ('商品3', 300);
COMMIT; -- 全て成功した場合のみ確定
インデックスを考慮したINSERT
-- 主キーの順番でINSERTすると効率的
INSERT INTO users (id, name, email)
VALUES
(1, 'ユーザー1', 'user1@example.com'),
(2, 'ユーザー2', 'user2@example.com'),
(3, 'ユーザー3', 'user3@example.com');
安全なINSERTのための注意点
SQLインジェクション対策
危険な例(プログラムでの動的SQL生成)
-- ❌ 危険:ユーザー入力をそのまま埋め込み
$sql = "INSERT INTO users (name) VALUES ('" . $_POST['name'] . "')";
安全な例(プリペアドステートメント使用)
// ✅ 安全:プリペアドステートメント
$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->execute([$name, $email]);
データの検証
-- 年齢の範囲チェック
INSERT INTO users (name, age)
VALUES ('田中太郎', 25)
WHERE 25 BETWEEN 0 AND 150; -- 実際にはアプリケーション側で検証
-- メールアドレスの形式チェック(アプリケーション側で実装)
トランザクション管理
START TRANSACTION;
INSERT INTO orders (customer_id, total_amount) VALUES (123, 5000);
SET @order_id = LAST_INSERT_ID();
INSERT INTO order_items (order_id, product_id, quantity) VALUES (@order_id, 1, 2);
INSERT INTO order_items (order_id, product_id, quantity) VALUES (@order_id, 2, 1);
-- エラーがあった場合はROLLBACK、成功した場合はCOMMIT
COMMIT;
デバッグとトラブルシューティング
INSERTの動作確認
1. テーブル構造の確認
DESCRIBE users;
-- または
SHOW CREATE TABLE users;
2. 制約の確認
SHOW CREATE TABLE users;
3. データの確認
-- INSERT後にデータを確認
SELECT * FROM users ORDER BY id DESC LIMIT 5;
よくある問題と解決法
問題1:文字化け
-- 文字エンコーディングを確認
SHOW VARIABLES LIKE 'character_set%';
-- UTF-8に設定
SET NAMES utf8mb4;
問題2:タイムゾーンの問題
-- タイムゾーンの確認
SELECT @@time_zone;
-- 日本時間に設定
SET time_zone = '+09:00';
問題3:権限エラー
-- 権限の確認
SHOW GRANTS FOR CURRENT_USER();
まとめ
MySQLのINSERT文は、データベースにデータを追加するための基本的で重要な操作です。
重要なポイント
- 基本構文:
INSERT INTO テーブル名 (カラム名) VALUES (値)
- 複数行INSERT:効率とパフォーマンスの向上
- AUTO_INCREMENT:自動採番カラムは省略可能
- 制約の理解:NOT NULL、UNIQUE、PRIMARY KEYなど
- エラー対処:適切なエラーメッセージの読み方
ベストプラクティス
- カラム名は明示的に指定する
- 複数行INSERTを活用する
- 適切なデータ型で値を指定する
- エラーハンドリングを適切に行う
- セキュリティを意識した実装にする
コメント