リレーショナルデータベースの基本となる「正規化」。おそらくRDBを使い慣れている人ならば、 テーブル定義を作っているうちに自然と正規化されたものが出来上がるのではないかと思います。
正規化というのはメンテナンス性やプログラムの簡略化を目的として行うものですが、 時には正規化することで逆にメンテナンス性が下がっているのではないかと感じる状況もあります。 例えば下記のような登録画面に対応するテーブル定義を考えてみましょう。
正規化された形でテーブルを定義するならば、下記のようになるはずです。 生徒情報を格納するstudentテーブルと、参加している部活動を格納するstudent_clubテーブル、 そして選択科目を格納するstudent_lessonテーブルの3つから構成されるわけですね。
ただ、student_clubテーブルとstudent_lessonテーブルをよく見ると、チェックボックスのためだけにテーブルが1つ生成されていることが分かります。 この例では2つだけですが、登録項目が増えた場合はそれに比例してテーブルもどんどん増えていくことになるのでしょう。 正規化としては綺麗にできているのですが、果たしてこの状態がメンテナンス性の良い状態かと問われると、首をかしげたくなります。
さて、ではどうするか。 項目が増えるごとにテーブルが増えるのが厄介なので、これらのテーブルを親となるstudentテーブルに押し込んで1つにまとめてしまえば良いのです。
ちなみに、1つにまとめると言っても下記のようないわゆる「横持ち」にするのは最悪で、 SELECT時の条件や画面表示の処理が複雑になるだけで、何もいいことがありません。
横持ちにせずテーブルを一つにまとめるには、チェックボックスで選択された値をカンマで連結し、 1つの文字列としてstudentテーブルに持たせればよいのです。 具体的には下記のようになります。
これでデータが1テーブルにまとまり、非常に見やすくコンパクトになりました。
さて、拡張されたstudentテーブルを見て「これ、検索するとき困るんでは?」と感じた方は、 おそらくRDBを良く使い慣れた方だと思います。
例えば英語Ⅱを選択している生徒を抽出する場合に「WHERE lessonIds LIKE "%1%"」のように書くと、 数学Ⅲの "21" や政治経済の "31" まで条件に引っかかってしまい、余計な行まで抽出されるためうまく行きません。
しかし、実はMySQLにはまさにこれ専用とも言える「FIND_IN_SET」という関数が用意されており、 この関数を使用することでごく単純に意図したデータを抽出することが可能です。
SELECT * FROM student WHERE FIND_IN_SET("1", lessonIds)
これで、気兼ねなくカンマ区切りのデータを登録することが出来ます。MySQLを採用するのであればぜひ知っておきたいテクニックです。