Je hebt een N:M-link nodig tussen books
en authors
, aangezien een boek meerdere auteurs kan hebben en elke auteur meer dan één boek kan hebben geschreven. In een RDBMS betekent dit dat je een written_by
. nodig hebt tafel.
De link tussen books
en publishers
is echter anders. Elk boek kan slechts één uitgever hebben (tenzij in uw systeem verschillende edities van een boek als hetzelfde boek worden beschouwd). Dus alles wat je hier nodig hebt is een publisher_id
buitenlandse sleutel in books
Ten slotte, en vooral, kijk je naar de lezers / gebruikers. En hun relatie tot boeken. Uiteraard is dit ook een N:M-relatie. Ik hoop echt dat mensen meer dan één boek lezen (we weten allemaal wat er gebeurt als je er maar één leest...) en zeker dat een boek door meer dan één persoon wordt gelezen. Dat vraagt om een book_users
aansluit tafel. De echte vraag hier is, hoe het te ontwerpen. Er zijn drie basisontwerpen.
-
Scheid tabellen op type relatie . (zoals geschetst door @just_somebody) Voordelen:Je hebt alleen INSERTS en DELETES, nooit UPDATES. Hoewel dit er netjes uitziet en enigszins helpt bij het optimaliseren van zoekopdrachten, heeft het meestal geen ander doel dan het tonen van een grote databasegrafiek.
-
Eén tabel met een
status
indicator . (zoals uiteengezet door @Hardcoded) Voordelen:Je hebt maar één tafel. Nadelen:je hebt INSERTS, UPDATES en DELETES - iets dat RDBMS gemakkelijk aankan, maar dat om verschillende redenen zijn gebreken heeft (daarover later meer) Ook een enkelestatus
veld houdt in dat één lezer slechts één verbinding met het boek tegelijk kan hebben, wat betekent dat hij zich alleen in deplan_to_read
kan bevinden ,is_reading
ofhas_read
status op elk moment in de tijd, en het veronderstelt een orde in de tijd dat dit gebeurt. Als die persoon ooit van plan zou zijn het opnieuw te lezen , of pauzeren, dan opnieuw lezen vanaf het begin etc, zo'n simpele reeks statusindicatoren kan gemakkelijk mislukken, omdat die persoon plotselingis_reading
nu, maar ookhas_read
het ding. Voor de meeste toepassingen is dit nog steeds een redelijke benadering, en er zijn meestal manieren om statusvelden zo te ontwerpen dat ze elkaar uitsluiten. -
Een logboek . U VOEGT elke status in als een nieuwe rij in een tabel - dezelfde combinatie van boek en lezer zal meer dan eens verschijnen. U INSERT de eerste rij met
plan_to_read
en een tijdstempel. Nog een metis_reading
. Dan nog een methas_read
. Voordelen:U hoeft alleen maar rijen IN te VOEREN en u krijgt een keurige chronologie van de dingen die zijn gebeurd. Nadelen:Cross-table-joins hebben nu te maken met veel meer gegevens (en zijn complexer) dan bij de eenvoudigere benaderingen hierboven.
U vraagt zich misschien af, waarom ligt de nadruk op INSERT, UPDATE of DELETE in welk scenario? Kortom, wanneer u een UPDATE- of DELETE-instructie uitvoert, is de kans groot dat u in feite verliest gegevens. Op dat moment moet je stoppen in je ontwerpproces en denken:"Wat verlies ik hier?" In dit geval verliest u de chronologische volgorde van gebeurtenissen. Als wat gebruikers doen met hun boeken het centrum van uw toepassing is, wilt u misschien zo veel mogelijk gegevens verzamelen. Zelfs als het er nu niet toe doet, is dat het type gegevens waarmee u later "magie" kunt doen. Je zou kunnen uitvinden hoe snel iemand leest, hoeveel pogingen ze nodig hebben om een boek uit te lezen, enz. Dat alles zonder de gebruiker om extra input te vragen.
Dus mijn laatste antwoord is eigenlijk een vraag:
Bewerken
Aangezien het misschien niet duidelijk is hoe een log eruit zou zien en hoe het zou werken, is hier een voorbeeld van zo'n tabel:
CREATE TABLE users_reading_log (
user_id INT,
book_id INT,
status ENUM('plans_to_read', 'is_reading', 'has_read'),
ts TIMESTAMP DEFAULT NOW()
)
In plaats van de tabel "user_read" in uw ontworpen schema bij te werken wanneer de status van een boek verandert, VOEG u nu dezelfde gegevens in het logboek in dat nu wordt gevuld met een chronologie van informatie:
INSERT INTO users_reading_log SET
user_id=1,
book_id=1,
status='plans_to_read';
Wanneer die persoon daadwerkelijk begint te lezen, doe je nog een invoeging:
INSERT INTO users_reading_log SET
user_id=1,
book_id=1,
status='is_reading';
enzovoort. Nu heb je een database met "gebeurtenissen" en aangezien de tijdstempelkolom zichzelf automatisch vult, kun je nu zien wat er wanneer is gebeurd. Houd er rekening mee dat dit systeem er niet voor zorgt dat er slechts één 'is_reading' voor een specifiek gebruikersboekpaar bestaat. Iemand kan stoppen met lezen en later verder gaan. Je deelnames zullen daar rekening mee moeten houden.