質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • MySQL

    6003questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

  • データベース設計

    149questions

    データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

注文詳細テーブルの外部キーである商品テーブルが更新された場合、購入当時の商品情報はどこに保存するのか

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 624

zendendo

score 27

実現したいこと・前提

railsでmysqlをつかっています。
通販のデータベース設計をしており、
過去の注文を見れるようにしたいと考えています。

よく通販のデータベース設計の例として
買い物の注文を確定させたとき、
注文テーブルと注文明細にレコードが作成され、
注文明細テーブルには、商品の情報が必要なので、商品テーブルを参照する外部キーが入っていると説明されています。

注文テーブル(注文詳細を多数保有している親テーブル)

id 注文日時 顧客(FK) 小計 手数料 支払合計額

注文詳細テーブル(一つの注文に従う子テーブル)

id 注文id(FK) 商品id(FK) 購入数量 単価

商品テーブル(多数の注文詳細から参照される親テーブル)

id 商品名 商品説明 価格

疑問点

ここでふと疑問に思ったのですが、
商品の更新(例えば、価格や説明文とかが変更)されたり、
販売中止とかで削除されてしまうと困ったことになるのではないかと。

例えば、
外部キー制約(RESTRICT)で、親テーブル(商品)の変更・削除を許さない場合は、
商品情報を更新できなくて困るかと思います。
かといって外部キー制約CASCADEにすると新しく更新された商品情報が子テーブルである注文詳細にも反映されてしまうため、購入した当時の商品情報を見ることができなくなってしまいます。
外部キー制約SET NULLにした場合も、購入当時の商品情報が見れなくなります。(また、頻繁に商品が更新されるのならば、注文明細の外部キーカラムがnullだらけで参照する意味が薄くなるのではないか?)

この場合、
購入当時のアイテム情報を見れるようにするにはどのテーブルに保存すればいいのでしょうか?
(新しいテーブルをつくるのか、または注文詳細テーブルに商品名、商品説明などをカラムを新たにつくって記録すればいいのでしょうか?)
教えて頂ければ幸いです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • xenbeat

    2018/06/17 18:08

    とりあえずタグに「データベース設計」を追加しましょう。

    キャンセル

  • zendendo

    2018/06/17 18:09

    追加します!

    キャンセル

  • xenbeat

    2018/06/17 18:09 編集

    「注文明細テーブルには、商品の情報が必要なので、商品テーブルを参照する外部キーが入っていると説明されています」→ 誰が説明しているのですか?どこかでそのような記事を見たのか、誰かに質問したのか等、具体的に追記ください。

    キャンセル

  • zendendo

    2018/06/17 18:27

    特定の誰かというわけではないのですが、ネットでdb設計をいくつか調べた際に、注文詳細に商品idを含めているものをいくつか見かけたのでそう書かせていただきました。参考サイトの内のひとつhttp://www.atmarkit.co.jp/ait/articles/0605/11/news124.html

    キャンセル

回答 2

checkベストアンサー

+5

購入当時のアイテム情報を見れるようにするにはどのテーブルに保存すればいいのでしょうか?
(新しいテーブルをつくるのか、または注文詳細テーブルに商品名、商品説明などをカラムを新たにつくって記録すればいいのでしょうか?)

結論から言うと、後者の注文詳細テーブルに商品名、商品説明などをカラムを新たにつくって記録が良いでしょう。

データベース設計を学ぶと、できるだけ正規化しましょうという考え方もありますが、
注文関連のテーブルみたいに、取引を記録するようなテーブルはあえて非正規化というアプローチを取ります。

 なぜ非正規化するのか

注文関連のテーブルは、いつ、誰に、何を、何個売り、合計はいくらで、いつ何で支払いされて、いつ何で納品するか等、
取引情報を時系列に記録するログファイルだと思ってください。

これらのテーブル(ログファイル)に挿入(記録)されたデータ(ログ)はイミュータブルであり、
そのデータを更新するということは、極端な言い方をすると取引データの改ざんとなります。

なので、注文された商品情報は、非正規化した注文関連のテーブルに、注文時点の情報をそのまま保持するのが良いという考えになります。

 補足

少し言葉足らずだったようなので補足。
既にご認識かと思いますが、ある商品が過去に何度か注文された後に、その商品の価格が変わったり、その商品が廃番になったりと、商品と注文のライフサイクルは異なります。
このように、ライフサイクルの異なるエンティティ同士はリレーションを張らないというのが設計的にはベストと言えるでしょう。
ただ、使用しているアプリケーションフレームワークで、リレーションを張らないといけない等の制約がありましたら、この限りではありません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/17 20:58

    maverixzさん、ありがとうございます。
    非正規の方がシンプルで理解しやすいです!今後は変更したくない履歴系の記録に入る外部キー(外から引っ張ってくる情報)には非正規化していきたいと思います。

    キャンセル

  • 2018/06/18 11:17

    それを非正規化と言うかは微妙ですが、外部キー制約は付けないことは忘れずに。

    キャンセル

  • 2018/06/19 10:42

    saziさん補足ありがとうございます!

    キャンセル

  • 2018/06/19 11:22

    追記部分についてコメントします。
    「非正規化=リレーションしない」ではないので、今回のトランザクション側に実績を残すというのは、「ボイス・コッド正規形」にまでは至らないので外部キー制約を外すという事だと思います。
    例えば、商品の実績を集計する場合には、取引の実績に商品コードが必要で、それは外部キーとしてリレーションの関係にはあります。

    キャンセル

  • 2018/06/19 11:48 編集

    > 「非正規化=リレーションしない」ではない

    確かにこれは確かに語弊が生まれるので修正します。

    > 例えば、商品の実績を集計する場合には、取引の実績に商品コードが必要で、それは外部キーとしてリレーションの関係にはあります。

    将来的に商品コードだって変わる可能性がありますので、取引の実績に商品コードを保持するのはもちろん同意で、ここにリレーションがあるかというところに認識齟齬があると思います。
    「コード」を保持するのでリレーションはあると言えばあると思うのですが、外部キー制約は付けない(ライフサイクルが異なるのでその時点の商品情報は注文に全て保持する)方が良いという考えです。

    キャンセル

  • 2018/06/19 11:57

    maverixzさんとの、認識は合っていると思っています。
    質問者さんが「(このようなケースは)非正規化していきたいと思います」というコメントを残されたのが気になりましたので、表現的なところだけです。

    キャンセル

  • 2018/06/19 11:59

    なるほどそういうことですね。
    諸々フォローありがとうございます!

    キャンセル

  • 2018/06/20 10:20 編集

    捕捉ありがとうございます。
    自分の用語の使い方と解釈が間違っていたかもしれないので、改めて平たくおさらいすると
    ・注文詳細テーブルに当時の情報を保存したい場合は外部キー制約は使わず、単なる商品コードとして記録する。
    ・注文詳細には、当時の商品情報を保存するため、商品名、商品説明、価格を追加して記録する。
    ということですね!

    カラム追加後の注文詳細テーブル
    id,注文id(FK),商品id,商品名、商品説明、価格、購入数量、単価

    キャンセル

0

カラムにその商品情報の開始時期・終了時期を作成する。

登録時にUPDATEをかけるのではなくINSERTをする。

時期によって表示を変えるプログラムを書く。

これらで出来ると思います。

回答になっていますか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/17 20:52

    van-0215さん、回答ありがとうございます。商品を更新替わりに作成していき、その中で最も新しいレコードだけを注文詳細テーブルの外部キーフィールドに入れるということでしょうか?

    キャンセル

関連した質問

同じタグがついた質問を見る

  • MySQL

    6003questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

  • データベース設計

    149questions

    データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

  • トップ
  • MySQLに関する質問
  • 注文詳細テーブルの外部キーである商品テーブルが更新された場合、購入当時の商品情報はどこに保存するのか