SQLite | ゼロからはじめるSQL、30日で習得するSQLite:データ操作・設計 - Day16 更新

SQL SQLite
スポンサーリンク

Day16 後半

「“一括で直す”UPDATE」と「絶対に壊さないための考え方」

前半で、UPDATE の基本
「どの行の」「どの列を」「どう書き換えるか」
は押さえました。

後半では、もう一歩踏み込んで、

  • 条件を工夫した“まとめて更新”
  • フラグ更新(状態を切り替える)
  • サブクエリを使った UPDATE の考え方
  • 「安全に UPDATE するためのチェック習慣」

を扱っていきます。

ここから先は、“強い力をどうコントロールするか” の話です。


状態フラグを UPDATE で切り替える

「active / inactive」「削除フラグ」を変える

実務で一番よく出てくる UPDATE は、
「状態フラグを切り替える」タイプです。

たとえば、users テーブルに is_active 列があるとします。

id | name       | is_active
---+------------+----------
 1 | 山田太郎   | 1
 2 | 佐藤花子   | 1
 3 | 鈴木一郎   | 1

ここで、「id=2 のユーザーを“無効化”したい」とします。

UPDATE users
SET is_active = 0
WHERE id = 2;
SQL

これで、id=2 だけが「アクティブ → 非アクティブ」に変わります。

さらに、「30歳以上のユーザーを一括で非アクティブにする」なら、こうです。

UPDATE users
SET is_active = 0
WHERE age >= 30;
SQL

ここで重要なのは、

「削除」ではなく「状態を変える」ことで、
“いつでも戻せる”余地を残している という点です。

セキュリティ的にも、
「物理削除(DELETE)ではなく論理削除(フラグ更新)」
はよく使われるパターンです。


日付や条件を使った“期間ベースの更新”

「一定期間ログインしていないユーザーを休眠扱いにする」

もう少し実務寄りの例にします。

userslast_login_atstatus があるとします。

id | name       | status   | last_login_at
---+------------+----------+-------------------
 1 | 山田太郎   | active   | 2025-04-01
 2 | 佐藤花子   | active   | 2023-01-01
 3 | 鈴木一郎   | active   | 2022-12-31

ここで、

「1年以上ログインしていないユーザーを status=’inactive’ にしたい」

という要件を考えます。

SQLite では日付関数を使って、こう書けます。

UPDATE users
SET status = 'inactive'
WHERE last_login_at < date('now', '-1 year');
SQL

ここでの流れは、

date('now', '-1 year') で「1年前の日付」を求める
last_login_at がそれより古いユーザーだけを対象にする
status を ‘inactive’ に更新する

というものです。

このように、
「時間 × 状態フラグ × UPDATE」
は、運用・セキュリティの両面でよく出てくるパターンです。


サブクエリを使った UPDATE の考え方

「別テーブルの情報をもとに、一括で値を更新する」

SQLite は一部の UPDATE JOIN が制限されますが、
考え方として「サブクエリで値を決めてから UPDATE する」パターンは重要です。

たとえば、usersuser_profiles があり、
user_profiles にだけ正しい年齢が入っているとします。

users
id | name       | age
---+------------+----
 1 | 山田太郎   | NULL
 2 | 佐藤花子   | NULL

user_profiles
user_id | real_age
--------+---------
1       | 25
2       | 19

「users.age を user_profiles.real_age で一括更新したい」とします。

SQLite では、JOIN を直接 UPDATE に書くのは難しいので、
まず SELECT で「どう更新されるべきか」を確認するのが鉄則です。

SELECT
  u.id,
  u.name,
  p.real_age
FROM users AS u
INNER JOIN user_profiles AS p
  ON u.id = p.user_id;
SQL

この結果を確認してから、
実際の UPDATE はアプリ側でループして行う、という設計もよくあります。

ここで大事なのは、

「まず SELECT で“更新後の姿”を確認してから、UPDATE を設計する」

という思考パターンです。

SQLite 単体での複雑な UPDATE は無理にやらず、
SELECT で“正しい対応表”を作ってから、アプリやスクリプトで反映する、
というのは現場でもよくあるやり方です。


UPDATE 前に必ずやるべき“安全確認”

「SELECT で対象行を確認する」「件数を数える」

UPDATE を安全に使うための、具体的なチェックを整理します。

一番大事なのは、
「UPDATE と同じ WHERE で、先に SELECT してみる」
ことです。

例:

SELECT *
FROM users
WHERE age >= 30;
SQL

で対象を確認してから、

UPDATE users
SET is_active = 0
WHERE age >= 30;
SQL

を実行する。

さらに一歩進めるなら、

SELECT COUNT(*) FROM users
WHERE age >= 30;
SQL

で「何件更新されるか」を事前に把握しておくのも有効です。

10件のつもりが 10,000 件だった
1件のつもりが 0 件だった

といった“違和感”に気づけるからです。

この「件数を数えてから UPDATE」は、
セキュリティというより “事故防止”のための最低限の防御線 です。


セキュリティの視点から見る「危険な UPDATE」

「WHERE なし」「広すぎる条件」「権限のない人の UPDATE」

UPDATE は、攻撃者にとっても“強い武器”です。

もしアプリケーションに脆弱な SQL 実行部分があり、
そこから UPDATE を自由に打てるとしたら、

全ユーザーのパスワードを無効化する
全ユーザーの is_admin を 1 にする
ログを改ざんして痕跡を消す

といったことが可能になります。

だからこそ、アプリ側では、

アプリケーションから実行できる UPDATE の内容を限定する
プレースホルダを使って、SQL インジェクションを防ぐ
管理系の UPDATE は、権限のあるユーザーだけに絞る

といった対策が必須になります。

Day16 の段階では、

「UPDATE は、攻撃者に渡してはいけない“超強力な権限”でもある」

という感覚だけ持っておいてくれれば十分です。


小さな練習で締める

日本語の「状態変更」を UPDATE に翻訳してみる

頭の中で、次の問いを SQL にしてみてください。

30歳以上のユーザーの status を ‘inactive’ にしたい。
1年以上ログインしていないユーザーの is_active を 0 にしたい。
一度もログインしていないユーザーの status を ‘pending’ にしたい(これは LEFT JOIN と組み合わせるイメージ)。

どれも、

UPDATE
SET 状態フラグ
WHERE 条件(ときに日付・JOIN・サブクエリ)

という型に当てはめれば書けるはずです。


Day16 後半のまとめ

UPDATE は「状態フラグの切り替え」「期間ベースの一括更新」など、実務で頻出する“運用の道具”。
UPDATE の前には、必ず同じ WHERE で SELECT して対象行と件数を確認するのが事故防止の基本。
複雑な更新は、まず SELECT で「どう更新されるべきか」を確認し、必要ならアプリ側で反映する設計も現実的。
UPDATE は、誤操作すればデータ破壊、悪用されればシステム破壊につながる“強い権限”であり、慎重な設計と権限管理が不可欠。

ここまで来たあなたは、
「読むだけの SQL」から一歩進んで、
「データの状態をコントロールする SQL」を扱える段階に入っています。
この先は、INSERT / DELETE、トランザクション、制約設計などと組み合わせて、より安全で堅いデータ操作の世界に進んでいけます。

タイトルとURLをコピーしました