sql >> Database >  >> RDS >> Mysql

Databaseschema voor boeken, auteurs, uitgevers en gebruikers met boekenplanken

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.

  1. 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.

  2. 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 enkele status veld houdt in dat één lezer slechts één verbinding met het boek tegelijk kan hebben, wat betekent dat hij zich alleen in de plan_to_read kan bevinden , is_reading of has_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 plotseling is_reading nu, maar ook has_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.

  3. 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 met is_reading . Dan nog een met has_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.



  1. Hoe een rij in SQL te verwijderen

  2. Hoe kan ik vergelijkbare rijen SELECTEREN in twee verschillende tabellen in MySQL (is dat mogelijk?)

  3. Programmatisch opgeslagen SQL Server-procedurebron ophalen die identiek is aan de bron die wordt geretourneerd door de SQL Server Management Studio-gui?

  4. Gegevens zijn nul. Deze methode of eigenschap kan niet worden aangeroepen voor null-waarden. (met keuzelijst)