sql >> Databasteknik >  >> RDS >> Mysql

Databasschema för böcker, författare, förlag och användare med bokhyllor

Du behöver en N:M-länk mellan books och authors , eftersom en bok kan ha flera författare och varje författare kan ha skrivit mer än en bok. I ett RDBMS betyder det att du behöver en written_by bord.

Länken mellan books och publishers är dock annorlunda. Varje given bok kan bara ha ett förlag (såvida inte olika utgåvor av en bok i ditt system anses vara samma bok). Så allt du behöver här är ett publisher_id främmande nyckel i books

Till sist, och viktigast av allt, tittar du på läsarna/användarna. Och deras relation till böcker. Naturligtvis är detta också en N:M relation. Jag hoppas verkligen att folk läser mer än en bok (vi vet alla vad som händer om man bara läser en...) och att en bok läses av mer än en person. Det kräver en book_users anslutningstabell. Den verkliga frågan här är hur man designar den. Det finns tre grundläggande design.

  1. Separera tabeller efter typ av relation . (som beskrivs av @just_somebody ) Fördelar:Du har bara INFOGA och TA BORT, aldrig UPPDATERINGAR. Även om det här ser ganska snyggt ut och till viss del hjälper till med frågeoptimering, tjänar det för det mesta inget annat ändamål än att visa upp ett stort databasdiagram.

  2. En tabell med status indikator . (som beskrivs av @Hardcoded) Fördelar:Du har bara en tabell. Nackdelar:Du kommer att ha INSLAG, UPPDATERINGAR och DELETE – något som RDBMS enkelt kan hantera, men som har sina brister av olika anledningar (mer om det senare) Dessutom en enda status fältet innebär att en läsare bara kan ha en anslutning till boken när som helst, vilket betyder att han bara kan vara i plan_to_read , is_reading eller has_read status vid vilken tidpunkt som helst, och det förutsätter en ordning i tid som detta händer. Om den personen någonsin skulle planera att läsa den igen , eller pausa, läs sedan om från början etc, en sådan enkel serie av statusindikatorer kan lätt misslyckas, eftersom den personen helt plötsligt is_reading nu, men också has_read saken. För de flesta applikationer är detta fortfarande ett rimligt tillvägagångssätt, och det finns vanligtvis sätt att utforma statusfält så att de utesluter varandra.

  3. En logg . Du INFOGA varje status som en ny rad i en tabell - samma kombination av bok och läsare kommer att dyka upp mer än en gång. Du INFOGA den första raden med plan_to_read , och en tidsstämpel. En annan med is_reading . Sedan en till med has_read . Fördelar:Du behöver bara INFOGA rader, och du får en snygg kronologi över saker som hände. Nackdelar:Korstabellkopplingar måste nu hantera mycket mer data (och vara mer komplexa) än i de enklare metoderna ovan.

Du kan fråga dig själv, varför ligger det tonvikten på om du INFOGA, UPPDATERA eller TA BORT i vilket scenario? Kort sagt, när du kör en UPDATE- eller DELETE-sats är det mycket sannolikt att du faktiskt förlorar data. Då måste du stanna upp i din designprocess och tänka "Vad är det jag förlorar här?" I det här fallet förlorar du händelsernas kronologiska ordning. Om det som användarna gör med sina böcker är centrum för din applikation, kan du mycket väl vilja samla in så mycket data du kan. Även om det inte spelar någon roll just nu, är det den typ av data som kan göra att du kan göra "magi" senare. Du kan ta reda på hur snabbt någon läser, hur många försök de behöver för att avsluta en bok, etc. Allt detta utan att be användaren om någon extra input.

Så mitt sista svar är faktiskt en fråga:

Redigera

Eftersom det kanske inte är klart hur en logg skulle se ut och hur den skulle fungera, är här ett exempel på en sådan tabell:

CREATE TABLE users_reading_log (
  user_id INT,
  book_id INT,
  status ENUM('plans_to_read', 'is_reading', 'has_read'),
  ts TIMESTAMP DEFAULT NOW()
)

Nu, istället för att uppdatera tabellen "user_read" i ditt designade schema när statusen för en bok ändras, INFOGA nu samma data i loggen som nu fylls med en kronologi av information:

INSERT INTO users_reading_log SET 
  user_id=1,
  book_id=1,
  status='plans_to_read';

När den personen faktiskt börjar läsa, infogar du en annan:

INSERT INTO users_reading_log SET 
  user_id=1,
  book_id=1,
  status='is_reading';

och så vidare. Nu har du en databas med "händelser" och eftersom tidsstämpelkolumnen automatiskt fylls av sig själv kan du nu berätta vad som hände när. Observera att det här systemet inte säkerställer att det bara finns en "läser" för ett specifikt användarbokspar. Någon kanske slutar läsa och senare fortsätter. Dina anslutningar måste stå för det.



  1. Ska jag använda en stor SQL Select-sats eller flera små?

  2. Anropar lagrad procedur med parameter Out med PDO

  3. Vad betyder följande Oracle-fel:ogiltigt kolumnindex

  4. MySQL-namnkonventioner, ska fältnamnet inkludera tabellnamnet?