状況
「企業 ID 42 の、plan が trial または expired のユーザを free に戻す」本番データ修正のダブルチェック中。company_id は整数列である。作業者が実行しようとしている SQL は次のとおり。
この SQL の最も危ない点は?
BEGIN;UPDATE users SET plan = 'free'WHERE company_id = 42 AND plan = 'trial' OR plan = 'expired';COMMIT;正答
- AND が OR より先に評価され、他社の expired ユーザも更新される
- BEGIN から COMMIT までの間、他の利用者が users を読めなくなる
- SET で変更する plan を WHERE でも使うと、正しく絞り込めない
- company_id = 42 は '42' と引用符で囲まないと一致しない
解説
SQL では AND が OR より先に評価されるため、この WHERE は「(company_id = 42 AND plan = 'trial') OR plan = 'expired'」と解釈され、全企業の expired ユーザが更新される。正しくは「company_id = 42 AND plan IN ('trial', 'expired')」のように括弧や IN で範囲を閉じる。多くの DB ではトランザクション中でも他の利用者は読み取りでき、SET と WHERE で同じ列を使うことにも問題はない。整数列に 42 を書くのも正しい。
この問題を含む 実務シチュエーション のテストを制限時間つきで解く
実務シチュエーションクイズへ