カスケード更新のパターン
4章 キーレスエントリ(外部キー嫌い)より
カスケード更新について考えてみる。
ON UPDATE、ON DELETE句には、RESTRICT, CASCADE, SET NULL, SET DEFAULT, NO ACTIONが指定できる。ただしMySQLにはSET DEFAULTは無い。
CREATE TABLE Bugs ( ... FOREIGN KEY (reported_by) REFERENCES Accounts(account_id) ON UPDATE CASCADE ON DELETE RESTRICT, FOREIGN KEY (status) REFERENCES BugStatus(status) ON UPDATE CASCADE ON DELETE SET DEFAULT );
Bugs.repotedy_by
で使われているAccounts.account_id
の行が削除された場合はエラーが発生する。これは適切だろうか。
Bugs.status
で使われているBugStatus
の行が削除された場合は、Bugs.status
にはデフォルト値"NEW"がセットされる。これは適切だろうか。
別の例を考えてみる。サンプルデータベースではCommentsテーブルの外部キーにON UPDATE、ON DELETE句は設定されていない。
CREATE TABLE Comments ( ... FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id), FOREIGN KEY (author) REFERENCES Accounts(account_id) );
ここにON UPDATE、ON DELETE句を書くとしたらどのように書くのが適切だろうか。
Bugsの行が削除された場合は、Comments.bug_id
に適当なデフォルト値は無さそうなのでSET DEFAULTは無いだろう。またNULLをセットしても、どのバグに対するものかという情報を失ったコメントに意味は無さそうに思える。なので、エラーにするか、カスケードに削除するかどちらかがよさそうに思える。
一方、Accountsの行が削除された場合は、Comments.author
はどうだろう。やはり適切なデフォルト値は無さそうだが、NULLにセットするのはありそうだ。誰が書いたかという情報を失なっても、バグに対するコメント自体は残しておきたいと思うかもしれないからだ。mixiのコミュニティとかでよく見た、投稿者が空欄になったコメントと同じだ。
(但し、サンプルデータベースではComments.authour
にNOT NULL制約が付いている)
こう感じるの裏側にはどんなパターンが隠れているのだろう。
Bugs.status
は遷移する状態を表しているので適切な初期状態に戻せば良い、と感じるのかもしれない「どのバグに対するコメントかわからないコメント」と「誰が書いたかわからないコメント」の情報量の違いをどう説明すればいいだろう
「誰が書いたかわからなバグレポート」と「誰が書いたかわからないコメント」についてはどうだろう
リソース系とイベント系という言葉でパターンにできないかと思ったけど上手くいかなかった。
あとON UPDATEについては、主キーが更新されることなんてめったに無いのだけれどあるとすれば自然キーを使っているときに番号の割り当てルールが変わったときなんかだろう(ISBNの桁数が変わったとか)。このサンプルデータベースではaccount_id
はSERIALなのでまずおこらないだろうけど。