ここでは、初心者から実践的に学べるプログラミングスクール「ウェブカツ!!」のWEBサービス部を受講している生徒の方向けにさらに「データベースのテーブル設計」についての理解度を上げるため特訓をしていきます。
ここでは「MySQL」を題材にします。
目次
DBのテーブル設計鬼練9:商品テーブルを作ろう
問題
ユーザーテーブルと同じように商品テーブル作りましょう。
下記の問題に答えてください。
下記の情報を保持しておくための商品情報のテーブル定義書を作成してください。
- 商品名
- 商品画像URL
- 詳細
- 金額
全て必須項目とします。
テーブル名は「products」としてください。
ヒント
分かりますよね。SQL鬼練の方でもやってるしね。
答え
答えは
ですね。
これはSQL鬼練でもほぼ同じなのが出てきましたね。
もちろん、カラム名は適当にそれらしい名前ならなんでもいいです。
商品というと「実物」なイメージですが、以前の鬼練でもやりましたが、サービスよって様々でしたね。
サービスによって、「記事」がここでいう「商品」と同じ意味であったり、エンジニア向けのエージェントサービスであれば「案件情報」がそれにあたりますしね。
ウェブカツというサービスで言えば、「部活」という情報がこの「商品」情報にあたりますね。
(ウェブカツのようなサービスの場合は、さらにその「部活(親商品)」に紐づいて、「練習(子商品)」というテーブルが必要です)
まず、商品テーブルにもIDをつけておきましょう。
これがないと
「https://XXXXX.com/product_detail.php?id=10」
みたいに商品一覧画面から「商品IDをURLにつけたリンク」を元にして「商品詳細画面」へ遷移する。
ってことが出来なくなりますからね。
(WEBサービス部でやりましたよね?分かってますよね?ここらへん)
商品のIDがわからなかったらどうやって情報を取ってきますか?
まさか、商品名から?
SQLで書くなら
1 |
SELECT * FROM products WHERE name = 'Mac book pro'; |
みたいな?
同じ名前の商品が他の人も登録していたらどうするの?
どうやって「どっちの商品」かを判別するの?
「ID」がなければ、できませんよね。
ユーザーテーブルに商品情報を持たせる!?
また、今回「商品テーブル」を作りましたが、初心者は
「ユーザーテーブル」に商品情報を持たせる
なんてやり方を考えたりもしがちです。
テーブル定義書で言えば、こんな感じです。
ユーザーが持っている情報、ユーザーが登録した商品なんだし、ユーザーテーブルに保存しておけばいいんじゃ?!
みたいな。
もちろん、こういうやり方をやれる場合もあります。
ただし、それは、
1つのユーザー(一人のユーザー)に対して1つの情報までしか持てない
場合のみ。です。
さっきのテーブル設計を見てみましょう。
これって、
1つのユーザーに1つの商品の情報
しか保存しておけませんよね?
もし、
2つ以上の商品(何かしらのコンテンツ)を登録したい場合は、1つ目の商品は削除する(自動的に削除されるのか、ユーザーがまず削除するのかはさておいて)
のであれば、これでもいいです。
でも、メルカリみたいに(というか何でもそうだけど)
1人のユーザーが1つの商品しか登録できないなんてことあります??
ないですよね。
1人のユーザーが複数の商品登録出来る。
というのが一般的なサービスです。
そうなるとこのテーブル設計では致命的なわけですね。
ユーザーテーブルだけで商品を複数登録する方法
ちなみに実はユーザーテーブルだけでも
「1人のユーザーに複数の商品登録が出来るようにする」
は実現できます。
どうやるか?というと
こうです。
商品情報系のカラムをどんどん増やす。
こうすればいけます。
この例だと商品が2つまで登録可能ですね。カラムをさらに増やせばもっと登録は出来ます。
ユーザーテーブルに複数商品を登録した場合のデメリット
「え、だったらこれでいいじゃん。」
と思ったそこのあなたはまだまだ初心者。
だって、そもそも
「商品の登録数って決まってるんですか?」
って話なわけです。
もし、本当に「1ユーザーにつき10商品までしか登録できない」としているのならこれでもいいです。
(と言っても、商品情報系のカラム3つを×10個作るの?めんどくね!?っていう気持ちになって欲しいですが。)
(と言っても、実際にテーブルを分割するよりかはテーブル1個に持たせた方が、SQLの実行速度は早いです。なので、登録上限が決まっているなら、実行速度最優先なのであればあえてこういう設計にする事もありますけどね)
でも、
「明日から商品登録の上限を10から50個に増やすから」
ってなったらどうするんです?
カラムを頑張って増やします?
その度に
「増やしたカラム1個1個にちゃんと値が入るか?更新されるか?」
を「テスト」しなければもちろんダメですね。
50個なら、商品情報系のカラム3個セット(商品名、詳細、金額)×50個を全部テストしなきゃダメですよ?
そうなれば、
「テスト工数=金」が商品登録数の上下によって必ず発生する
わけです。
あなたは「金食い虫エンジニア」なんでしょうか?
お客さんのコストを出来るだけ下げてあげたいですよね?
そういうためにあなたはお客さんから金をもらうわけですから。
(とは言っても、将来を考えすぎて、考える事自体に時間=工数=客の金を使ってしまっては元も子もないですけどね。とは言え、そこに考える時間をあまり割かなくてもパッと設計が出来るくらいには最終的にならなきゃいけませんがね。)
昔からある「台帳」
じゃあ、そこでどうするか?
というので、
テーブルを分ける
という結論になるわけですね。
昔ながらの「紙媒体」で顧客情報を管理していた時も結局同じです。
「顧客台帳」と「商品台帳」みたいに「台帳を分ける」ことを昔からしていたわけです。
台帳を分けつつ、「その商品はどの顧客のものなのか」が分かるようにしておけばいいわけです。
なので、今回のテーブルが出来上がるわけです。
逆に商品テーブルにユーザー情報を持たせる
また、初心者のテーブル設計であるあるなのが
「商品テーブルにユーザー情報を持たせる」
というもの。
テーブル定義で見るとこんな感じです。
「ニックネーム」「氏名」「メールアドレス」なんかを
ユーザーが商品登録をした時点で商品テーブルに一緒にぶっこむようにする
というものですね。
登録した商品に「その時の登録者名やら情報」っていっしょにくっついてない?保存しておく必要あるんじゃない?
みたいな考えからこうなりがちです。
(さすがに「パスワード」も一緒に保存しておこうという発想にはならないとは思ってますが。)
もちろん、それも「あり」です。
ただし、
「商品をユーザーが登録した時点の情報からユーザー情報が変わらないものなのであれば」
です。
商品テーブルにユーザー情報を持たせるデメリット
ユーザーのemailって変わるかもしれませんよね?
ニックネームだってそうですね。
ユーザーがemailを変更する場合、プロフィール編集画面的なところから普通変えるでしょう。
そうするとアプリ側でどういう処理を通常しますか?
ユーザーテーブルのemailカラムをUPDATEする。
ですよね。
え、商品情報のemailは変えないんですか?
こういうテーブル設計の場合、変えなきゃいけませんよね。
もし、メルカリみたいな「買い手と売り手」みたいに2種類のユーザーがいる場合どうなりますか?
商品買おうとemailからコンタクト取ろうとしても取れない。(だってメアド変わってんだもん。)
ってことになるわけです。
「え?コンタクトはユーザーテーブルのemailを取得して、そのemailへ行えばよくない?」
なんて、もし、もし、もしもあなたが思ったとしたら、僕はこう言いたい。
「だったら、商品情報に登録したemailって何のためにあるの?」
ってこと。
使わないもん登録してもしょうがないですよね。
こういったように
「更新される可能性がある情報」
を
「ユーザーテーブル」「商品テーブル」の両方に保存しておく。
のは管理がしにくくなります。
(ユーザー情報が変更されたら、合わせてそのユーザーが登録した全商品の情報の中のユーザー情報を変える処理をしなきゃいけない。)
だから、
- ユーザー情報はユーザーテーブルで管理する
- 商品情報は商品テーブルで管理する
ときちんと分けてあげて、
「テーブル間での情報のダブリをなくす」
ということが大切なわけですね。
(それが、「正規化」と呼ばれるものでしたね)