books
間にN:Mリンクが必要です およびauthors
、1つの本に複数の著者がいて、各著者が複数の本を書いている可能性があるためです。 RDBMSでは、written_by
が必要になることを意味します テーブル。
books
間のリンク およびpublishers
ただし、異なります。特定の本は1つの出版社しか持つことができません(システム内で本の異なる版が同じ本と見なされない限り)。したがって、ここで必要なのはpublisher_id
だけです。 books
の外部キー
最後に、そして最も重要なのは、読者/ユーザーを見ていることです。そして本との関係。当然、これもN:Mの関係です。きっと人々が複数の本を読んでくれることを願っています(あなたが一度だけ読んだらどうなるかは誰もが知っています...)そして確かに本は複数の人に読まれます。 book_users
が必要です 接続テーブル。ここでの本当の問題は、それをどのように設計するかです。 3つの基本的なデザインがあります。
-
リレーションのタイプごとにテーブルを分ける 。 (@just_somebodyで概説されています)利点:INSERTSとDELETESのみがあり、UPDATESはありません。これは見た目はすっきりしていて、クエリの最適化には多少役立ちますが、ほとんどの場合、大きなデータベースチャートを表示する以外の実際の目的には役立ちません。
-
status
を持つ1つのテーブル インジケーター 。 (@Hardcodedで概説)利点:テーブルは1つだけです。短所:INSERTS、UPDATES、およびDELETESがあります。RDBMSは簡単に処理できますが、さまざまな理由で欠点があります(詳細は後で説明します)。また、単一のstatus
フィールドは、1人の読者がいつでも本に1つしか接続できないことを意味します。つまり、彼はplan_to_read
にしか存在できません。 、is_reading
またはhas_read
任意の時点でのステータスであり、これが発生する時間の順序を想定しています。その人がそれをもう一度読むことを計画している場合は 、または一時停止してから最初から読み直すなど、このような単純な一連のステータスインジケータは、突然その人がis_reading
するため、簡単に失敗する可能性があります。 今だけでなく、has_read
事。ほとんどのアプリケーションでは、これは依然として合理的なアプローチであり、通常、ステータスフィールドを相互に排他的に設計する方法があります。 -
ログ 。すべてのステータスをテーブルの新しい行として挿入します。ブックとリーダーの同じ組み合わせが複数回表示されます。
plan_to_read
を使用して最初の行を挿入します 、およびタイムスタンプ。is_reading
のもう1つ 。次に、has_read
を含む別のコード 。利点:行を挿入するだけで済み、発生したことのきちんとした年表が得られます。短所:クロステーブル結合では、上記の単純なアプローチよりもはるかに多くのデータを処理する必要があります(そしてより複雑になります)。
どのシナリオでINSERT、UPDATE、またはDELETEを使用するかが重要視されるのはなぜですか?つまり、UPDATEまたはDELETEステートメントを実行するたびに、実際には失う可能性が非常に高くなります。 データ。その時点で、設計プロセスを停止して、「ここで何を失っているのか」を考える必要があります。この場合、イベントの時系列の順序が失われます。ユーザーが自分の本で行っていることがアプリケーションの中心である場合は、できるだけ多くのデータを収集することをお勧めします。今は問題ではありませんが、それは後で「魔法」を実行できる可能性のあるデータの種類です。誰かがどれだけ速く読んでいるか、本を完成させるために何回試行する必要があるかなどを知ることができます。これらすべては、ユーザーに追加の入力を求めることなく行われます。
ですから、私の最終的な答えは実際には質問です:
編集
ログがどのように表示され、どのように機能するかが明確でない可能性があるため、このようなテーブルの例を次に示します。
CREATE TABLE users_reading_log (
user_id INT,
book_id INT,
status ENUM('plans_to_read', 'is_reading', 'has_read'),
ts TIMESTAMP DEFAULT NOW()
)
これで、本のステータスが変更されるたびに設計されたスキーマの「user_read」テーブルを更新する代わりに、同じデータをログに挿入して、情報の時系列を入力できるようになりました。
INSERT INTO users_reading_log SET
user_id=1,
book_id=1,
status='plans_to_read';
その人が実際に読み始めたら、別の挿入を行います:
INSERT INTO users_reading_log SET
user_id=1,
book_id=1,
status='is_reading';
等々。これで「イベント」のデータベースが作成され、タイムスタンプ列が自動的にいっぱいになるため、いつ何が起こったかを知ることができます。このシステムでは、特定のユーザーと本のペアに対して「is_reading」が1つだけ存在することは保証されないことに注意してください。誰かが読むのをやめて、後で続けるかもしれません。参加はそれを説明する必要があります。