SQLとACID — 絞ってから集めるか、集めてから絞るか
「店舗ごとの売上合計を出して、1,000万円を超えた店舗だけ表示したい」——この「絞り込み」、合計を出す前の行への条件と、合計を出した後のグループへの条件は、SQLでは別の言葉です。ここを混ぜるのが定番の的。
そしてもう1つの主役が、銀行振込を支える4つの約束(ACID)です。
WHEREとHAVINGはどう使い分け、ACID特性は何を保証しているのでしょうか。
WHEREは集約前の行、HAVINGは集約後のグループに効きます
WHEREはグループ分け(集約)の前に、1行1行を絞り込む条件——「今月の売上データだけ」。HAVINGはGROUP BYで集約した後に、グループ(集計結果)を絞り込む条件——「合計が1,000万円を超えた店舗だけ」。絞ってから集めるのがWHERE、集めてから絞るのがHAVINGです。
ACIDは銀行振込で考えます——A口座から引き落とし、B口座へ入金という2つの操作は、原子性(全部やるか全部やらないか——片方だけは許さない)・一貫性(残高の整合が崩れない)・独立性(他の処理の途中経過が混ざらない)・耐久性(完了した取引は障害でも消えない)の4つの約束で守られています。
命令の4分類と、分離レベルの両端も持ち帰ります
SQLの命令は4分類——DML(データ操作:SELECT・INSERT・UPDATE・DELETE)・DDL(定義:CREATE・ALTER・DROP・TRUNCATE)・DCL(権限:GRANT・REVOKE)・TCL(トランザクション制御:COMMIT・ROLLBACK・SAVEPOINT)。表の結合(JOIN)にはINNER・LEFT/RIGHT/FULL OUTER・CROSSがあります。
独立性の強さはトランザクション分離レベルで調整します——最弱のREAD UNCOMMITTEDでは他の処理の未確定データまで読めてしまい(ダーティリード)、反復不能読み取り・ファントムリードも起きうる。最強のSERIALIZABLEは3つの異常を全て防ぐ代わりに、同時実行の性能が落ちます。「強いほど安全、弱いほど速い」のトレードオフです。
WHERE/HAVINGの取り違えと、TRUNCATEの分類が的です
定番の誤り肢は「集約後の条件をWHEREで書く」——集計結果(SUMやCOUNT)への条件はHAVINGです。逆に「集約前の行の絞り込みにHAVINGを使う」も誤り。集約の前か後かだけで判定できます。
命令の分類ではTRUNCATEが的——表の全行を消すので DELETE(DML)の仲間に見えますが、分類はDDLです。分離レベルは「SERIALIZABLEはダーティリードが発生する」型の入れ替え——最強レベルは全て防ぐ、が正です。
診断士がSQLを書く場面は多くありませんが、BIツールやPOS分析のフィルタ設計でWHERE/HAVINGの区別はそのまま生きます——「単価500円以上の商品だけ集計」(集約前=WHERE相当)と「合計が100万円超のカテゴリだけ表示」(集約後=HAVING相当)は別のフィルタです。ACIDは会計システムの信頼性を顧問先に説明する語彙——「仕訳が中途半端に残らないのは原子性のおかげ」です。
冒頭の問いに答えます。WHEREは集約前の行の絞り込み、HAVINGは集約後のグループの絞り込み——「絞ってから集めるか、集めてから絞るか」です。ACIDは原子性(全部か無か)・一貫性・独立性・耐久性の4つの約束で取引を守り、独立性の強さは分離レベル(最弱READ UNCOMMITTED〜最強SERIALIZABLE)で調整します。次は、システムをどう作り進めるか——開発モデルへ。