マルチカラムアトリビュート

ジェイウォークのように繰返し項目をテーブルを分割せずに対応する方法の一つ。ジェイウォークは区切り文字を使って一つの属性に押し込めていたが、このパターンでは繰返し項目を単に番号をつけて列を分割する。
例えば、住所録に電話番号を複数格納する必要がある場合に、属性に「電話番号1」「電話番号2」・・・ともたせる設計である。
データベース設計の初心者が行うような設計であり、さすがに慣れた人がこのような設計をすることはないと思われる。
問題が発生する理由は以下のとおり。

検索が大変

常にすべての属性に対しOR条件で取得する必要があり、SQLが複雑になる。OR条件が足りない場合はバグの温床ともなる。

値の追加と削除が大変

値を追加しようにもどこが空いているかを確認して代入する必要がある。SQLだけでは面倒である。

一意性の保証ができない

複数の属性に同じ値を入れたくなくても制約が設定できないので、設定できない

列が足りないかも

繰返し項目がいくつあっても足りないかもしれない。余裕を見て属性を設計すると、殆どの項目がNULLとなり、テーブル自体の見通しが悪くなる。また、繰返し項目が追加されると、先程までの検索・削除・追加の仕組みを全て作り直す必要がある。

アンチパターンを使ってもいい場合

単なる繰り返しだけではなく、それぞれに意味がある場合は使ってもいいというもの。監訳の注記にもあるようにその場合は「XXXX1」などではなく、その意味に従った名前にすべきであると私も思う。
その他、私が格納しても良い、と思える状況は以下のとおりである。

  • 該当項目を条件にして検索をしない
  • 一部の値の更新や削除をしない

つまり、上記の問題を起こさないことがほぼ確実であれば、構わない。このような条件に沿うものであれば、別に列が足りなくなっても増やすことには特に問題ない。
また、更新や削除についてだが、プログラム側で上記を管理しないのであればよい。つまり、値を詰めたり、削除したり、一意性を保証したりといったことはすべて人任せなら問題ない。
さて、具体的にはこれにはどのような場合に使えるだろうか?あまり使える場面は少ないが、例えば「備考」だろうか?この「備考」は帳票などに印刷ができるように固定のN行まで使うことができる。
この1行毎に「備考1」「備考2」・・・「備考N」などと設定ができる。
ただし、この備考という属性はとても曲者で、とても重要な情報をこの中に格納してしまうことがあり、このような設計が正しいとはとてもいいきれないが、単なるメモなのであれば、このような使い方も可能である。

対応策

テーブルを分ける。ほとんどの場合はこれでよい。