やる気がストロングZERO

やる気のストロングスタイル

【テーブル設計】削除フラグを使わず削除テーブルを使うべき

データの削除機能において、何らかの理由でデータは残しておきたい場合には「削除フラグ」が使われがちだが、これは絶対にやめたい。
この場合は「削除テーブル」を用意してそちらにデータを移し、元テーブルからはレコード削除を行うようにするべきだと思っている。
それについて書く。

削除フラグを使うと事故りやすい

シチュエーション:販売終了商品が削除フラグ=1でテーブルに残っている

例えばある商品が販売されていたが、今は販売されていない商品が以下のようなテーブルとレコードで表現されているとする。

id 商品名 価格 削除フラグ
1 ガム 100 1
2 キャンディ 120 0

id: 1のガムは今はもう販売されていないので削除フラグが1(true)になっている。
しかし、商品購入履歴などで必要なのでデータはそのまま残っている。

商品テーブルに削除商品があることを常に意識してないとすぐ事故る

「取り扱い商品一覧データ」を取得する際[WHERE 削除フラグ != 1]の記載を忘れるともう事故になる。
これくらいだったら「そんな間違いをする方が悪い」のかもしれないが「常に意識しないといけない」というのが地味に難易度が高い。

  • 「外部の業者とのやりとりで必要なので商品データ一式をcsvでちょうだい」とかパッと言われてクエリを書く時
  • 新機能実装中、ユーザー毎の販売商品数が必要なので商品テーブルをjoinしようとした時
  • 新しくアサインされた新人が商品テーブルを使ったなんらかの集計値を算出する時

どんな状況でも、なにか商品テーブルに関する事を行う時には必ず削除フラグの事を意識しないといけない。
一度でも忘れると、表示されてはいけないデータが表示されたりして事故になる。
なかなか厳しいのではないかと思う。

こんなのがそこかしらのテーブル内に○○フラグ、××フラグといくつもあったりするともうお手上げ。

「削除商品テーブル」を用意して削除時はそちらにデータを移す

テーブル設計

テーブル定義はこんな感じ。頭文字をあわせることで関連したテーブルがテーブルリストで近なるようにしている。

商品全部テーブル(販売履歴など、商品とのリレーションはこのテーブルと行う)

id
1
2

商品販売中テーブル

id 商品名 価格
2 キャンディ 120

商品販売終了テーブル

id 商品名 価格
1 ガム 120

明示的に削除商品テーブルをJOINしない限り削除商品のデータが混じってしまうことはない

基本的に商品販売中テーブルを扱って作業するようになるので、特に気をつけないといけないことはない。
削除した商品のデータが必要な時は明示的に商品販売終了テーブルをJOINせねばならない。 直感的だと思う。

まとめ

そもそもリレーショナルモデルにて集合は「状態」を扱わない。
フラグを持たせて状態を管理しだすとリレーショナルモデルから外れるためDBがカバーしきれなくなりアプリケーション側で面倒を見てやらねばならなくなる、というのが今回の問題の原因である。

だから、削除フラグを使わず削除テーブルを使うべきである。

参考図書)