状況
BAN 済みユーザーを users から消す作業。作業者は「DELETE の前に同じ条件で数えます」と言い、次の SELECT を実行した。users は 5 行。banned は 2 行で、列は user_id と reason。
この SELECT の結果は?
SELECT COUNT(*) AS n FROM usersWHERE id IN (SELECT id FROM banned);正答
- 2。banned の 2 人だけが一致するので、DELETE に進んでよい
- エラー。banned に id 列がないので、DELETE も失敗して安全
- 0。列名が違うので何も一致せず、DELETE しても何も消えない
- 5。id が外側の users.id と解釈され、全件が一致する
解説
banned に id 列がないため、サブクエリ内の id は外側の users.id として解釈され(相関サブクエリ)、「自分の id が自分の id の集合に含まれるか」になって全行が一致する。エラーにならないので気づきにくく、このまま DELETE に置き換えると users が全件消える。正しくは SELECT user_id FROM banned。確認で 2 ではなく 5 が出た時点で止まれるかが分かれ目。banned.id と表名付きで書けば誤りはエラーになる。
参考: www.sqlite.org
この問題を含む 危険察知 のテストを制限時間つきで解く
危険察知クイズへ