【SQL UPDATE入門】SETとWHEREを使いこなし既存データを安全に更新する方法
ユーザーがメールアドレスを変更した、商品の価格が改定された、ブログ記事が「下書き」から「公開」に変わった――。Webアプリケーションを運用していると、一度登録したデータを後から変更したい場面は日常的に発生します。この「既存のデータを書き換える」という重要な役割を担うのが、SQLのUPDATE文です。
UPDATE文は、データベースのレコードを新しい情報に更新するための命令です。しかし、この命令は非常に強力であると同時に、一つのミスが取り返しのつかない事態を引き起こす危険性も秘めています。その運命を分けるのが、WHERE句の存在です。
この記事では、UPDATE文の基本的な使い方から、複数カラムの同時更新といった応用テクニックまでを解説します。そして何よりも、「絶対にWHERE句を忘れてはいけない」という鉄の掟を、皆さんの心に刻み込んでもらうことを最大の目標とします。コピペで動くコードを試しながら、安全かつ確実にデータを更新するスキルを身につけていきましょう。
準備:更新対象のユーザーデータを用意しよう
操作を試すには、元となるデータが必要です。今回は、シンプルなユーザー情報を管理するusersテーブルを作成し、何人かのユーザーを登録しておきましょう。この記事の例はすべて、このテーブルを対象とします。
-- もしusersテーブルが存在すれば削除(繰り返し試せるように)
DROP TABLE IF EXISTS users;
-- 新しいusersテーブルを作成
CREATE TABLE users (
id INTEGER PRIMARY KEY,
username TEXT NOT NULL,
email TEXT NOT NULL,
points INTEGER DEFAULT 0,
last_login_date DATE
);
-- 初期データを挿入
INSERT INTO users (id, username, email, points, last_login_date) VALUES
(1, '山田 太郎', 'yamada@example.com', 50, '2025-06-15'),
(2, '鈴木 花子', 'suzuki@example.com', 120, '2025-06-20'),
(3, '田中 次郎', 'tanaka@example.com', 300, '2025-06-28'),
(4, '佐藤 美咲', 'sato@example.com', 550, '2025-06-30'),
(5, '伊藤 健太', 'ito@example.com', 80, '2025-05-30');
これで、更新操作を試すための5人のユーザーデータが準備できました。
最重要:`WHERE`句を忘れる恐怖(全件更新の危険性)
本編に入る前に、まずUPDATE文で最もやってはいけない、最悪の失敗例からお見せします。それは、WHERE句を付け忘れることです。
UPDATE文の基本構造はUPDATE テーブル名 SET 列名 = 新しい値 WHERE 条件;です。このWHERE句は「どのレコードを更新するか」を指定する、いわば更新対象を絞り込むための安全装置です。もし、この安全装置を付け忘れると、一体何が起こるのでしょうか?
例えば、「全ユーザーのポイントをキャンペーンで50ポイントに統一しよう!」と思って、焦って次のようなクエリを実行してしまったとします。
-- 【絶対に安易に実行しないこと!】WHERE句を忘れたUPDATE文
UPDATE users SET points = 50;
このクエリにはWHERE句がありません。すると、データベースは「usersテーブルのすべてのレコードについて、points列を50にせよ」と解釈します。その結果、苦労して貯めた550ポイントを持つ佐藤さんのデータも、他の全ユーザーのデータも、すべて無慈悲に50ポイントに書き換えられてしまいます。
これは、特定の人物に用事があったのに、部屋にいる全員に「おい、お前だ!」と叫んでしまうようなものです。UPDATE文を使うときは、指差し確認するくらいの気持ちで、必ずWHERE句で更新対象を明確に指定してください。これがUPDATE文を学ぶ上での絶対のルールです。
【基本】特定のレコードを1件だけ更新する
では、気を取り直して正しい使い方を見ていきましょう。最も基本的なのは、主キー(idなど)を使って、特定の1件のレコードだけを更新するケースです。これなら更新対象が間違いなく1件に定まるので安全です。
シナリオ:「IDが3の田中さんのメールアドレスが変更になった」
UPDATE users
SET email = 'jiro.tanaka@new-example.com'
WHERE id = 3;
WHERE id = 3と指定することで、更新対象をIDが3のレコードだけに正確に絞り込んでいます。SET句で、email列の値を新しいアドレスに書き換えています。
更新されたか確認してみましょう。SELECT文でIDが3のユーザーだけを表示してみます。
SELECT * FROM users WHERE id = 3;
実行結果:
id | username | email | points | last_login_date
---|----------|-----------------------------|--------|----------------
3 | 田中 次郎 | jiro.tanaka@new-example.com | 300 | 2025-06-28
emailが正しく更新されているのがわかりますね。これがUPDATE文の基本にして、最も安全な使い方です。
【応用1】複数のカラムを同時に更新する
一度に複数の列の値を更新したい場合もよくあります。例えば、ユーザーがログインした時に、最終ログイン日時と所持ポイントの両方を更新する、といったケースです。
SET句に、更新したい「列名 = 値」のペアをカンマ(,)で区切って複数記述することで、一度に更新できます。
シナリオ:「IDが2の鈴木さんがログインしたので、最終ログイン日を更新し、ログインボーナスとして10ポイントを加算する」
UPDATE users
SET
last_login_date = '2025-07-01',
points = 130
WHERE
id = 2;
このように、SET句に複数の更新内容を記述するだけで、効率的にデータを更新できます。
【応用2】条件に合う複数のレコードをまとめて更新する
WHERE句の条件は、主キーだけでなく、他の列の値を使うこともできます。これにより、特定の条件に合致する複数のレコードを一括で更新することが可能です。
シナリオ:「現在300ポイント以上持っている全ユーザーに、ボーナスとして100ポイントをプレゼントする」
この場合、更新対象は「pointsが300以上のユーザー」です。また、新しいポイントは「現在のポイント + 100」となります。UPDATE文では、このように自身の列の現在の値を使って計算した結果で更新することもできます。
UPDATE users
SET points = points + 100
WHERE points >= 300;
このクエリを実行すると、IDが3の田中さん(300ポイント)とIDが4の佐藤さん(550ポイント)のポイントが、それぞれ400と650に更新されます。特定のユーザー層に向けたキャンペーンなどで頻繁に使われる、非常に実用的なテクニックです。
【体験コーナー】ブラウザでSQLを動かし、安全なデータ更新を体験しよう!
さあ、ここまでの知識をあなたのスキルとして定着させましょう。以下のHTMLコードを丸ごとコピーしてsql_update_test.htmlのようなファイル名で保存し、ブラウザで開いてみてください。この記事で使っているusersテーブルが用意された、あなた専用のSQL実行環境が立ち上がります。
まずは、WHERE句をしっかり使って、安全にデータを更新する練習をしてみましょう。誰かのポイントを変えてみたり、メールアドレスを更新したりしてみてください。更新前と更新後でSELECT * FROM users;を実行して、結果がどう変わるかをその目で確かめるのが上達への一番の近道です。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SQL UPDATE文 オンライン実行環境</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: #f39c12; color: white; border: none; padding: 12px 22px; font-size: 16px; border-radius: 6px; cursor: pointer; transition: background-color 0.2s; }
button:hover { background-color: #d35400; }
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>下のテキストエリアにUPDATE文やSELECT文を入力して「実行」ボタンを押してください。ID=5の伊藤さんのポイントを更新してみましょう!</p>
<textarea id="sql-input">-- 更新前のID=5のユーザーデータを確認
SELECT * FROM users WHERE id = 5;
-- ID=5の伊藤さんのポイントを200に更新
UPDATE users
SET points = 200
WHERE id = 5;
-- 更新後の全ユーザーデータを表示して確認
SELECT * FROM users;
</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 users;
CREATE TABLE users (
id INTEGER PRIMARY KEY,
username TEXT NOT NULL,
email TEXT NOT NULL,
points INTEGER DEFAULT 0,
last_login_date DATE
);
INSERT INTO users (id, username, email, points, last_login_date) VALUES
(1, '山田 太郎', 'yamada@example.com', 50, '2025-06-15'),
(2, '鈴木 花子', 'suzuki@example.com', 120, '2025-06-20'),
(3, '田中 次郎', 'tanaka@example.com', 300, '2025-06-28'),
(4, '佐藤 美咲', 'sato@example.com', 550, '2025-06-30'),
(5, '伊藤 健太', 'ito@example.com', 80, '2025-05-30');
`;
db.run(setupSql);
executeBtn.disabled = false;
executeBtn.textContent = '実行';
statusMsg.textContent = '準備完了!UPDATE文でデータを更新し、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('UPDATE') || trimmedStmt.toUpperCase().startsWith('INSERT') || 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>
UPDATEの仲間たち:CRUD操作
UPDATEをマスターしたあなたは、データ操作の基本であるCRUD(クラッド)のうち、3つ目の力を手に入れました。
- C (Create): 新しいデータを作成する →
INSERT文 - R (Read): データを読み取る →
SELECT文 - U (Update): 既存のデータを更新する →
UPDATE文(今回マスターしました!) - D (Delete): 既存のデータを削除する →
DELETE文
データを「作り」「読み」「更新する」ことができるようになった今、残るは「削除(DELETE)」です。これを覚えれば、あなたはデータベースの基本的な操作をすべて行えるようになります。ゴールはもうすぐです!
まとめ
今回は、既存のデータを安全に更新するためのUPDATE文について、その重要性と使い方を学びました。
- 最大の鉄則:
UPDATE文には必ずWHERE句を付ける。付け忘れると、テーブルの全データが更新されてしまいます。 - 基本構文:
UPDATE テーブル名 SET 列 = 値 WHERE 条件;が基本形。 - 複数カラム更新:
SET句にカンマ区切りで列 = 値を複数並べることで、一度に更新できる。 - 複数レコード更新:
WHERE句の条件を工夫することで、条件に合う複数のレコードを一括更新できる。自身の値を使った計算(points = points + 100)も可能。
INSERTがデータの「誕生」だとすれば、UPDATEはデータの「成長」や「変化」を司る操作です。ユーザー情報の変更やステータスの更新など、動的なWebアプリケーションには不可欠な機能です。WHERE句という安全装置の重要性を常に意識しながら、データの更新操作に慣れていきましょう。この力を正しく使えれば、あなたの作れるアプリケーションの幅は格段に広がります。