はじめに
複数チェックボックスを DB 保存する際あり得ないデータ構造にあたったので愚痴を含んだ忘備録として記載します。
ちなみに今回ぶち当たった設計は「数値に変換して保存する」で実装されていました。実装した人や関わった人がもういないのでなんでこんな設計にしたのかは不明です。
要件
- 1月~12月をチェックボックスで選ばせる(複数可)
- 画面イメージ
設計方法
テーブル分割する
まず第1に検討すべき方法です。むしろこの方針を採用しない理由が逆に聞きたいものです。
テーブル構成を表1に示します。選択月のみ/未選択も保存の検討は必要ですが、その他は特段検討する内容はないです。
カラム名 | 型 |
id | int |
object_id | int |
month | int(2) |
MySQL の Set 型で保存する
MySQL には配列を保持する Set 型[1]があり、これで保存します。
文字列で保存する or バイナリで保存する
1月~12月を12桁で数値で表現し、 チェックがあるところを1、ないところを0とします。
例えば 1月, 3月にチェックがある場合は「1010000000」を保存します。
Json型で保存する
MySQL には配列を保持する Json 型[2]があり、これで保存します。
例えば 1月, 3月にチェックがある場合は「{‘january’ => true, ‘february’ => false, ’march’ => true, …}」を保存します。
数値に変換して保存する
1月~12月を2進数表現の数値に当てはめ、かつ総計で保存します。表2に月と数値の対応表を示します
月 | 2進数表現 | 10進数表現 |
1月 | 1 | 1 |
2月 | 10 | 2 |
3月 | 100 | 4 |
4月 | 1000 | 8 |
例えば 1月, 3月にチェックがある場合は「5」を保存します。
各項目をカラムで保存する
1月~12月用のカラムを用意し、それぞれの値を保存します。
感想
保存方法6パターン記載しましたが、下に行くほどアンチパターンとなっていきます。
DB の値を見た際に意味が分からない、検索できないなどデメリットしかありません。
今回、int 型に保存されており、データ見ても意味が分かりませんでした。使っているロジックを追ってようやく把握しましたが、読む人にやさしくない設計です。2018年に設計されたシステムでこんな設計がされているとはという感想でした。
ダメ変な設計
参考
[1] 11.3.6 The SET Type, https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/checkbox
[2] 11.5 JSON データ型, https://dev.mysql.com/doc/refman/8.0/ja/json.html
コメント