Sie benötigen eine N:M-Verknüpfung zwischen books
und authors
, da ein Buch mehrere Autoren haben kann und jeder Autor mehr als ein Buch geschrieben haben kann. In einem RDBMS bedeutet dies, dass Sie einen written_by
benötigen Tabelle.
Die Verbindung zwischen books
und publishers
ist jedoch anders. Jedes Buch kann nur einen Verlag haben (es sei denn, in Ihrem System werden verschiedene Ausgaben eines Buchs als dasselbe Buch betrachtet). Alles, was Sie hier brauchen, ist also eine publisher_id
Fremdschlüssel in books
Zuletzt und vor allem schauen Sie sich die Leser / Benutzer an. Und ihre Beziehung zu Büchern. Auch hier handelt es sich natürlich um eine N:M-Beziehung. Ich hoffe sehr, dass die Leute mehr als ein Buch lesen (wir alle wissen, was passiert, wenn man immer nur eins liest...) und sicherlich wird ein Buch von mehr als einer Person gelesen. Das erfordert ein book_users
Verbindungstabelle. Die eigentliche Frage ist hier, wie man es gestaltet. Es gibt drei Grunddesigns.
-
Tabellen nach Art der Beziehung trennen . (wie von @just_somebody beschrieben) Vorteile:Sie haben nur INSERTS und DELETES, niemals UPDATES. Das sieht zwar nett aus und hilft bei der Abfrageoptimierung, aber meistens dient es keinem anderen Zweck als der Darstellung eines großen Datenbankdiagramms.
-
Eine Tabelle mit einem
status
Indikator . (wie von @Hardcoded beschrieben) Vorteile:Sie haben nur eine Tabelle. Nachteile:Sie haben INSERTS, UPDATES und DELETES - etwas, das RDBMS leicht handhaben kann, das aber aus verschiedenen Gründen seine Fehler hat (dazu später mehr) Außerdem einen einzigenstatus
Feld impliziert, dass ein Leser zu jedem Zeitpunkt nur eine Verbindung zu dem Buch haben kann, d. h. er kann nur implan_to_read
sein ,is_reading
oderhas_read
Status zu jedem Zeitpunkt, und es geht von einer zeitlichen Reihenfolge aus, in der dies geschieht. Falls diese Person jemals vorhaben würde, es nochmals zu lesen , oder pausieren, dann von Anfang an neu lesen usw., kann eine solch einfache Reihe von Statusanzeigen leicht fehlschlagen, weil diese Person plötzlichis_reading
jetzt, sondern auchhas_read
die Sache. Für die meisten Anwendungen ist dies immer noch ein vernünftiger Ansatz, und es gibt normalerweise Möglichkeiten, Statusfelder so zu gestalten, dass sie sich gegenseitig ausschließen. -
Ein Protokoll . Sie FÜGEN jeden Status als neue Zeile in eine Tabelle ein - die gleiche Kombination aus Buch und Lesegerät erscheint mehr als einmal. Sie fügen die erste Zeile mit
plan_to_read
ein , und einen Zeitstempel. Ein weiterer mitis_reading
. Dann noch eins mithas_read
. Vorteile:Sie müssen immer nur Zeilen EINFÜGEN und erhalten eine übersichtliche Chronologie der Ereignisse. Nachteile:Kreuztabellen-Joins müssen jetzt viel mehr Daten verarbeiten (und komplexer sein) als bei den einfacheren Ansätzen oben.
Sie fragen sich vielleicht, warum die Betonung darauf liegt, ob Sie in welchem Szenario EINFÜGEN, AKTUALISIEREN oder LÖSCHEN? Kurz gesagt, wann immer Sie eine UPDATE- oder DELETE-Anweisung ausführen, werden Sie sehr wahrscheinlich tatsächlich verlieren Daten. An diesem Punkt müssen Sie in Ihrem Designprozess anhalten und denken:"Was verliere ich hier?" In diesem Fall geht die chronologische Reihenfolge der Ereignisse verloren. Wenn das, was Benutzer mit ihren Büchern tun, im Mittelpunkt Ihrer Anwendung steht, möchten Sie möglicherweise so viele Daten wie möglich sammeln. Auch wenn es im Moment keine Rolle spielt, das ist die Art von Daten, mit denen Sie später vielleicht "zaubern" können. Sie könnten herausfinden, wie schnell jemand liest, wie viele Versuche er braucht, um ein Buch zu beenden usw. All dies, ohne den Benutzer um zusätzliche Eingaben zu bitten.
Meine endgültige Antwort ist also eigentlich eine Frage:
Bearbeiten
Da es möglicherweise nicht klar ist, wie ein Protokoll aussehen und wie es funktionieren würde, ist hier ein Beispiel für eine solche Tabelle:
CREATE TABLE users_reading_log (
user_id INT,
book_id INT,
status ENUM('plans_to_read', 'is_reading', 'has_read'),
ts TIMESTAMP DEFAULT NOW()
)
Anstatt die "user_read"-Tabelle in Ihrem entworfenen Schema zu aktualisieren, wann immer sich der Status eines Buches ändert, fügen Sie jetzt dieselben Daten in das Protokoll ein, das sich jetzt mit einer Chronologie von Informationen füllt:
INSERT INTO users_reading_log SET
user_id=1,
book_id=1,
status='plans_to_read';
Wenn diese Person tatsächlich mit dem Lesen beginnt, machen Sie eine weitere Einfügung:
INSERT INTO users_reading_log SET
user_id=1,
book_id=1,
status='is_reading';
und so weiter. Jetzt haben Sie eine Datenbank mit "Ereignissen" und da sich die Zeitstempelspalte automatisch füllt, können Sie jetzt erkennen, was wann passiert ist. Bitte beachten Sie, dass dieses System nicht sicherstellt, dass nur ein „is_reading“ für ein bestimmtes Benutzerbuchpaar existiert. Jemand könnte aufhören zu lesen und später weiterlesen. Ihre Joins müssen dies berücksichtigen.