SQL INSERT文で新しいデータを追加する前に確認すること
Webサイトの会員登録、ブログの新規投稿、ECサイトの商品登録…。Webアプリケーションが活気づくのは、新しいデータが次々と生まれるからです。この「新しいデータをデータベースに登録する」という最も基本的で重要な操作を担うのが、SQLのINSERT文です。
INSERT文は、データベースという巨大な台帳に新しい行を書き込むための命令です。その構文は一見シンプルですが、一行だけの追加から複数行の一括登録、さらには別のテーブルからのデータコピーまで、多彩な使い方があります。しかし、シンプルなだけに、ちょっとした間違いでエラーが出てしまい、初心者がつまずきやすいポイントでもあります。
この記事では、INSERT文の基本的な書き方に加えて、ロリポップなどの本番MySQLで実行する前に何を確認するか、フォーム投稿やAIが出したSQLをそのまま使ってよいかを整理します。練習用SQLと本番DB操作を分けて、安全に追加できる状態を作りましょう。
確認日: 2026年5月19日
このページで整理できること
INSERT INTO ... VALUESの基本形と、列名を省略しない理由。- フォーム投稿、管理画面、初期データ投入で、INSERT前に確認する項目。
- 主キー、NOT NULL、データ型、文字コードなど、追加時に出やすいエラーの見方。
- AIやCodexが出したINSERT文を、本番DBへ入れる前に止めて確認する観点。
最初に分けること
| 状況 | 先に確認すること | 次に読むページ |
|---|---|---|
| 練習用テーブルでINSERTを覚えたい | 列名、値の順番、追加後のSELECT確認をセットにする | SQL SELECTの基本 |
| フォーム投稿をDBへ保存したい | 入力チェック、空欄、重複、保存してよい個人情報を決める | PHPフォームの安全対策 |
| ロリポップのMySQLで実行したい | 接続先DB、テーブル名、文字コード、バックアップの有無を確認する | PDOでロリポップMySQLへ接続 |
| AIがINSERT文を書いてくれた | 本番DB名、接続情報、個人情報をAIへ貼らず、テスト環境で先に確認する | AIコード安全公開の入口 |
先に確認:INSERTはSELECTで確認しながら覚える
INSERT はデータを増やす命令です。練習中でも、本番DBでも、実行後は必ず SELECT で追加結果を確認します。
- まだ取得の基本が曖昧なら、先に SQLのSELECT文の基本 を確認します。
- 追加したデータだけ確認したい時は、WHERE句でデータを絞り込む方法 を使います。
- 新しい順に確認したい時は、ORDER BYで並び替える方法 が役立ちます。
- PHPから登録するなら、PHPフォームの安全対策 とセットで考えます。
準備:データを追加するためのテーブルを用意しよう
データを追加するには、まずそのデータを入れておくための「箱」、つまりテーブルが必要です。今回は、新商品の情報を管理するproductsというテーブルを作成してみましょう。このテーブルは、この記事を通してずっと使っていきます。
注目すべきはid列のINTEGER PRIMARY KEYです。多くのデータベース(SQLite、MySQLのAUTO_INCREMENTなど)では、このように設定すると、データを追加するたびにユニークなIDが自動で割り振られるようになります。これが後ほど重要になります。
-- もしproductsテーブルが存在すれば削除(繰り返し試せるように)
DROP TABLE IF EXISTS products;
-- 新しいproductsテーブルを作成
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
category TEXT,
price INTEGER,
release_date DATE
);
これで、商品データを登録するための空っぽのテーブルが用意できました。早速、このテーブルに新しい命を吹き込んでいきましょう。
【基本】INSERT INTO ... VALUES: 1行のデータを追加する
まずはINSERT文の基本形、「1行のデータを追加する」方法です。構文はINSERT INTO テーブル名 (列1, 列2, ...) VALUES (値1, 値2, ...);となります。()内の列リストとVALUESの後の値リストが、順番通りに1対1で対応するのがポイントです。
INSERT INTO products (name, category, price, release_date)
VALUES ('奇跡のリンゴ', '食品', 500, '2025-07-01');
このクエリを実行すると、productsテーブルに新しい商品が1件追加されます。id列は指定していませんが、テーブル作成時に自動で番号が振られるように設定したため、データベースが自動的に1を割り当ててくれます。これが主キー(PRIMARY KEY)を自動採番にする大きなメリットです。
追加されたか確認してみましょう。SELECT * FROM products;を実行すると、今追加したデータが表示されるはずです。
SELECT * FROM products;
実行結果:
id | name | category | price | release_date
---|-------------|----------|-------|-------------
1 | 奇跡のリンゴ | 食品 | 500 | 2025-07-01
また、一部の列の値がまだ決まっていない場合(NULLが許可されている列に限る)、その列を省略してINSERTすることも可能です。
-- 価格(price)と発売日(release_date)を省略してINSERT
INSERT INTO products (name, category)
VALUES ('幻の桃', '食品');
この場合、priceとrelease_dateにはNULL(値なし)が入ります。
【応用1】複数行のデータを一括で追加する
新商品を一つずつ登録するのは少し面倒ですね。INSERT文では、複数のデータを一度のクエリでまとめて追加することができます。
書き方は簡単で、VALUESの後に()で囲んだ値のリストをカンマ(,)で区切って並べるだけです。これにより、データベースとの通信が1回で済み、1行ずつINSERTを繰り返すよりも効率が良くなります。
INSERT INTO products (name, category, price, release_date) VALUES
('魔法のキーボード', 'ガジェット', 12000, '2025-07-10'),
('虹色マウス', 'ガジェット', 5000, '2025-07-20'),
('天空のブドウ', '食品', 2500, '2025-08-01');
この1つのクエリで、3つの商品データが一気に追加されました。初期データの投入や、CSVファイルから読み込んだデータをまとめて登録する際などに非常に便利なテクニックです。
【応用2】`INSERT ... SELECT`文で他のテーブルからデータをコピーする
これは中級者向けの非常に強力なテクニックです。INSERT ... SELECT文を使うと、別のテーブルからSELECT文で取得した結果を、そのまま新しいテーブルに追加することができます。
例えば、「入荷予定リスト」テーブル(new_arrivals)から、正式に発売が決まった商品だけをproductsテーブルに移す、といったシナリオで大活躍します。
まず、コピー元となるnew_arrivalsテーブルを作成し、データを登録しておきましょう。
-- コピー元のテーブルを作成
CREATE TABLE new_arrivals (
product_name TEXT NOT NULL,
product_category TEXT,
list_price INTEGER,
launch_date DATE,
is_confirmed INTEGER -- 発売が確定したら1、そうでなければ0
);
-- 入荷予定リストにデータを登録
INSERT INTO new_arrivals VALUES
('究極のヘッドフォン', 'オーディオ', 28000, '2025-09-01', 1),
('未来のVRゴーグル', 'ガジェット', 75000, '2025-10-01', 1),
('全自動コーヒーメーカー', '家電', 18000, '2025-09-15', 0);
準備ができました。それでは、new_arrivalsテーブルから発売が確定している(is_confirmed = 1)商品だけを選び出し、productsテーブルに追加しましょう。
INSERT INTO products (name, category, price, release_date)
SELECT product_name, product_category, list_price, launch_date
FROM new_arrivals
WHERE is_confirmed = 1;
このクエリのポイントは、VALUES句の代わりにSELECT文が使われている点です。SELECT文で取得される列の構成(列の数、順序、データ型)が、INSERT INTO products (...)で指定された列構成と一致している必要があります。データのバックアップや、集計結果を別のテーブルに保存する際など、用途は非常に幅広いです。
初心者がつまずくINSERT文のエラーと対処法
INSERT文は、データベースのルール(制約)を破るとすぐにエラーを返します。ここでは、初心者が遭遇しがちな代表的なエラーとその原因、対処法を見ていきましょう。
エラー1:主キー(PRIMARY KEY)の重複
これは最もよく見るエラーです。主キーはテーブル内で絶対に重複してはならない、唯一の識別子です。もし手動でIDを指定していて、すでに使われているIDを再び使おうとするとエラーになります。
例えば、ID=1の「奇跡のリンゴ」はすでに登録されています。もう一度ID=1で新しい商品を登録しようとすると…
-- これはエラーになります!
INSERT INTO products (id, name, category, price, release_date)
VALUES (1, '別のリンゴ', '食品', 300, '2025-07-02');
これを実行すると、UNIQUE constraint failed: products.id や Duplicate entry '1' for key 'PRIMARY' といったエラーメッセージが表示されます。
対処法: 主キーは手動で管理せず、データベースの自動採番機能に任せるのが最も安全で確実です。最初の例のように、INSERT文の列リストにidを含めないようにしましょう。
エラー2:NOT NULL制約違反
テーブル作成時にNOT NULLと指定した列は、必ず値を入れる必要があります。この列を省略してINSERTしようとするとエラーになります。
productsテーブルのname列はNOT NULLです。もしnameを指定せずにINSERTしようとすると…
-- これもエラーになります!
INSERT INTO products (category, price)
VALUES ('その他', 1000);
NOT NULL constraint failed: products.name のようなエラーが表示されます。
対処法: NOT NULL制約のある列には、必ず何らかの値を指定してください。もし空の文字列でも許容したい場合は、''のように指定します。
エラー3:データ型の不一致
テーブル定義で定められたデータ型と違う型のデータを入れようとするとエラーになります。例えば、数値型(INTEGER)のprice列に文字列を入れようとするケースです。
-- これも当然エラーになります!
INSERT INTO products (name, price)
VALUES ('高価な石', '値段は秘密');
Datatype mismatch や Incorrect integer value: '値段は秘密' for column 'price' のようなエラーが出ます。
対処法: テーブルの定義をよく確認し、各列に合ったデータ型の値を指定してください。数値を文字列として'500'のようにクォートで囲んでしまうミスもよくあるので注意しましょう。
エラーが出た時は、まず「どの列の制約に引っかかったか」を読みます。ロリポップやPHPからMySQLへ登録する時に接続や文字化けで迷う場合は、PHP PDOでロリポップのMySQLへ接続する方法、本番でエラーが見えない場合は ロリポップでPHPエラーログを見る方法 も確認してください。
本番DBでINSERTを使う前に止まる場所
INSERTは削除ほど危険に見えませんが、重複データ、間違った顧客情報、テスト投稿、文字化けした本文を増やしてしまうことがあります。本番DBで実行する前は、次を確認してから進めます。
- 今触っている接続先が、ローカル、テスト、本番のどれかを確認する。
- 追加先テーブルの列名と、
NOT NULL、主キー、ユニーク制約を確認する。 - フォームから受け取る値は、空欄、長すぎる文字、想定外の文字を弾く。
- 個人情報や問い合わせ内容を保存する場合は、保存目的と削除方法を先に決める。
- 実行後は必ず
SELECTとWHEREで、追加した行だけを確認する。
本番DBの操作に不安がある場合は、先に ロリポップで自作PHPサイトを安全に更新する入口 と AIが出したコードを本番に入れる前の確認入口 へ戻って、作業範囲を整理してください。
AIにSQLのINSERT文について相談するメモ
AIやCodexへ相談する時は、DB接続情報や実データをそのまま貼らず、構造と目的だけを渡します。
SQLのINSERT文について相談します。
目的:
- フォーム投稿 / 管理画面 / 初期データ投入 のどれか:
環境:
- ローカル / テスト / 本番:
- DB種別: MySQL / SQLite / その他
- PHPから実行するか: はい / いいえ
テーブル構造:
- テーブル名:
- 追加したい列:
- NOT NULL、主キー、ユニーク制約:
確認したいこと:
- 列名と値の対応が正しいか
- 重複や空欄をどう防ぐか
- 実行後にSELECTでどう確認するか
貼らない情報:
- DBホスト、ユーザー名、パスワード
- 実在する個人情報、メールアドレス、問い合わせ本文
- 本番の管理画面URL
【体験コーナー】ブラウザでSQLを動かして、データを追加してみよう!
さあ、知識をスキルに変える時間です! 以下のHTMLコードを丸ごとコピーして、sql_insert_test.htmlのようなファイル名で保存し、ブラウザで開いてみてください。あなた専用のSQL実行環境が立ち上がり、この記事で作成したproductsテーブルが用意されています。
自由にINSERT文を書いて「実行」ボタンを押し、そのすぐ下にSELECT * FROM products;を書いて再度「実行」して、データが本当に追加されたか確かめてみましょう。エラーをわざと起こしてみるのも、良い勉強になりますよ!
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SQL INSERT文 オンライン実行環境</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; line-height: 1.7; color: #333; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
h1 { color: #2c3e50; }
textarea { width: 100%; height: 180px; font-family: "SF Mono", "Consolas", monospace; font-size: 16px; padding: 12px; border: 1px solid #ccc; border-radius: 6px; box-sizing: border-box; margin-bottom: 1rem; }
button { background-color: #27ae60; color: white; border: none; padding: 12px 22px; font-size: 16px; border-radius: 6px; cursor: pointer; transition: background-color 0.2s; }
button:hover { background-color: #229954; }
button:disabled { background-color: #bdc3c7; cursor: not-allowed; }
#result-container { margin-top: 2rem; border: 1px solid #ddd; padding: 1rem; border-radius: 6px; background: #fdfdfd; min-height: 50px; }
#status-message { color: #27ae60; font-weight: bold; }
#error-message { color: #e74c3c; font-weight: bold; }
table { border-collapse: collapse; width: 100%; margin-top: 1rem; }
th, td { border: 1px solid #ddd; padding: 10px; text-align: left; }
th { background-color: #f2f2f2; }
tr:nth-child(even) { background-color: #f9f9f9; }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/sql-wasm.js"></script>
</head>
<body>
<h1>SQLを試してみよう!</h1>
<p>下のテキストエリアにSQL文を入力して「実行」ボタンを押してください。自分で考えた商品のINSERT文を試してみましょう!</p>
<textarea id="sql-input">-- ここにINSERT文やSELECT文を書いてみよう
INSERT INTO products (name, category, price, release_date)
VALUES ('無重力チェア', '家具', 45000, '2025-11-11');
SELECT * FROM products;
</textarea>
<button id="execute-btn">実行</button>
<div id="result-container">
<p id="status-message"></p>
<p id="error-message"></p>
<div id="result-output"></div>
</div>
<script>
const sqlInput = document.getElementById('sql-input');
const executeBtn = document.getElementById('execute-btn');
const statusMsg = document.getElementById('status-message');
const errorMsg = document.getElementById('error-message');
const resultOutput = document.getElementById('result-output');
let db;
async function initDb() {
executeBtn.disabled = true;
executeBtn.textContent = 'DB準備中...';
try {
const SQL = await initSqlJs({
locateFile: file => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/${file}`
});
db = new SQL.Database();
const setupSql = `
DROP TABLE IF EXISTS products;
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
category TEXT,
price INTEGER,
release_date DATE
);
`;
db.run(setupSql);
executeBtn.disabled = false;
executeBtn.textContent = '実行';
statusMsg.textContent = '準備完了!INSERT文でデータを追加し、SELECT文で結果を確認してみましょう。';
} catch (err) {
errorMsg.textContent = 'データベースの初期化に失敗しました: ' + err.message;
console.error(err);
}
}
function executeSql() {
if (!db) return;
const sql = sqlInput.value;
statusMsg.textContent = '';
errorMsg.textContent = '';
resultOutput.innerHTML = '';
try {
const statements = sql.split(';').filter(s => s.trim() !== '');
let lastResult;
statements.forEach(stmt => {
const trimmedStmt = stmt.trim();
if (trimmedStmt.toUpperCase().startsWith('INSERT') || trimmedStmt.toUpperCase().startsWith('UPDATE') || trimmedStmt.toUpperCase().startsWith('DELETE')) {
db.run(trimmedStmt);
const changes = db.getRowsModified();
statusMsg.innerHTML += `クエリ「${trimmedStmt.substring(0, 30)}...」が実行され、${changes}行が変更されました。<br>`;
} else {
const results = db.exec(trimmedStmt);
lastResult = results;
}
});
if (lastResult && lastResult.length > 0) {
lastResult.forEach(result => {
const table = document.createElement('table');
const thead = document.createElement('thead');
const tbody = document.createElement('tbody');
const headerRow = document.createElement('tr');
result.columns.forEach(colName => {
const th = document.createElement('th');
th.textContent = colName;
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
result.values.forEach(row => {
const bodyRow = document.createElement('tr');
row.forEach(cellValue => {
const td = document.createElement('td');
td.textContent = cellValue === null ? 'NULL' : cellValue;
bodyRow.appendChild(td);
});
tbody.appendChild(bodyRow);
});
table.appendChild(thead);
table.appendChild(tbody);
resultOutput.appendChild(table);
});
}
} catch (err) {
errorMsg.textContent = 'SQLエラー: ' + err.message;
console.error(err);
}
}
executeBtn.addEventListener('click', executeSql);
initDb();
</script>
</body>
</html>
INSERTの仲間たち:CRUD操作
INSERTを覚えたあなたは、データベース操作の基本的な4つの力のうち、1つを手に入れたことになります。この4つの操作は、それぞれの頭文字をとってCRUD(クラッド)と呼ばれ、あらゆるアプリケーションのデータ操作の基礎となります。
- C (Create): 新しいデータを作成する →
INSERT文(今回学びました!) - R (Read): データを読み取る →
SELECT文 - U (Update): 既存のデータを更新する →
UPDATE文 - D (Delete): 既存のデータを削除する →
DELETE文
SELECTはすでにおなじみですね。データを「追加」できるようになった今、次は「更新(UPDATE)」や「削除(DELETE)」の方法を学んでいくと、データベースでできることの幅がさらに大きく広がります。
CRUDをPHPで動かす流れまで見たい場合は、PHPで簡単なCRUD掲示板を作る方法 が次の実践候補です。更新は UPDATEとWHEREの安全な使い方、削除は DELETEでレコードを安全に削除する方法 を先に読んでから試すと事故を避けやすくなります。
まとめ
今回は、データベースに新しいデータを追加するためのINSERT文について、その基本から応用、そして注意すべきエラーまでを詳しく見てきました。
- 基本構文:
INSERT INTO テーブル (列...) VALUES (値...);が全ての基礎。 - 主キー: 自動採番に設定すれば、IDの管理をデータベースに任せられて安全・確実。
- 複数行INSERT:
VALUES句に複数の値リストをカンマで繋げることで、一括登録が可能。 - INSERT SELECT: 別のテーブルから取得したデータを丸ごと追加できる強力なテクニック。
- エラー対処: 「主キー重複」「NOT NULL違反」「データ型不一致」が三大エラー。原因を理解すれば怖くない。
INSERT文は、あなたのWebサイトやアプリケーションに命を吹き込み、ユーザーのアクションを記録し、コンテンツを豊かにするための最初のステップです。この記事の体験コーナーで何度も練習し、データを自由自在に追加する感覚を掴んでください。この小さな成功体験の積み重ねが、あなたを一流のWebクリエーターへと導いてくれるはずです。