危険察知4 択難易度 応用

状況

BAN 済みユーザーを users から消す作業。作業者は「DELETE の前に同じ条件で数えます」と言い、次の SELECT を実行した。users は 5 行。banned は 2 行で、列は user_id と reason。

この SELECT の結果は?

SELECT COUNT(*) AS n FROM usersWHERE id IN (SELECT id FROM banned);

正答

  1. 2。banned の 2 人だけが一致するので、DELETE に進んでよい
  2. エラー。banned に id 列がないので、DELETE も失敗して安全
  3. 0。列名が違うので何も一致せず、DELETE しても何も消えない
  4. 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

sqlsubquerydelete

この問題を含む 危険察知 のテストを制限時間つきで解く

危険察知クイズへ