Du må være registrert og logget inn for å kunne legge ut innlegg på freak.no
X
LOGG INN
... eller du kan registrere deg nå
Dette nettstedet er avhengig av annonseinntekter for å holde driften og videre utvikling igang. Vi liker ikke reklame heller, men alternativene er ikke mange. Vær snill å vurder å slå av annonseblokkering, eller å abonnere på en reklamefri utgave av nettstedet.
  11 2265
I mitt lille eksempel så lagrer jeg filmer, hver film skal ha informasjon om sjanger/kategori og en beskrivelse av filmen.

Eksempel:



Med tanke på at det finnes et gitt antall forskjellige sjangre, så tenker jeg at jeg har en egen tabell med sjangre å velge imellom, slik at jeg unngår å ha repetative data i film-tabellen. Jeg vet at en film kan ha flere sjangre, men i dette eksempelet så sier vi at en film kun kan ha én sjanger. Dette vil altså si at jeg må ha et one-to-many relationship, hvor one=filmer, og many=sjangre.

Dette blir seende slik ut:


Det som er problematisk, er at nå blir det litt bakvendt. Jeg vil jo definere kategorien som tilhører filmen når jeg oppretter en ny film, men nå er det slik at jeg først må definere filmen, så må jeg gå til kategori-tabellen og legge til filmen der etterpå. Dette virker ikke hensiktsmessig?


Dersom jeg gjør det motsatt som dette:


Da kan jeg spesifisere kategorien i foreign key feltet på hver film, men da blir det jo filmen som har many? Hva er det jeg har missforstått her? Databaser er skikkelig forvirrende
NOOOOOOOOOOOOOOOOOO-
robhol's Avatar
Hvis man skal være litt pedantisk: det du "egentlig" vil ha er et mange-til-mange-forhold, fordi en sjanger kan ha mange filmer og en film kan ha mange sjangre.

Hvis du velger å vilkårlig bestemme at en film bare skal kunne ha én sjanger, blir dette en enkel kolonne på Film, det er mao. løsning #2 som er riktig og løsning #1 som er veldig, veldig feil.

Da er det fortsatt Kategori som har "en"-delen fordi mange filmer kan peke på én kategori mens kategorien ikke peker på noe som helst.

Det er lett å overtenke dette en tanke... tegn et røft diagram med penn og papir, så blir det lettere.
Sist endret av robhol; 7. september 2017 kl. 14:50.
Tusen takk for svar robhol!

Kanskje jeg kan spørre deg om en helt annen ting? Når man begynner å få litt størrelse og kompleksitet på databasen, og kanskje har flere nivåer med many-to-many referansetabeller, blir det ikke etterhvert svært mange steg man må ta for å querie data?

Eksempel:


Dette er jo et litt teit eksempel, men la oss si at du er på en film, og ønsker å hente ut venner av produsenten for filmen, da må man slik jeg ser det gå igjennom følgende prosedyre:
  1. Hente ut IDen til den aktuelle filmen
  2. Sjekke referansetabellen FilmRegissører etter IDen til filmen, og sjekke hvilken RegissørID som tilhører FilmIDen
  3. Søke igjennom referansetabellen RegissørVenner etter RegissørIDen, og sjekke hvilken VennerID som tilhører RegissørIDen
  4. Søke igjennom tabellen Venner etter alle VennerIDene vi har hentet ut

Grunnen til at dette er et dårlig eksempel er at det ikke er hensiktsmessig å finne ut hvilke venner regissøren av en gitt film har, men la oss si at det ville ha vært en ting man trengte å gjøre ofte. Finnes det noen enklere/bedre måte å gjøre det på? Blir ikke databasen veldig treg dersom man må gjøre fullstendige søk i flere tabeller for å finne informasjon om en film? Er det noen triks jeg har gått glipp av, eller er dette måten man gjør det på?
Sist endret av stepry; 7. september 2017 kl. 17:03.
Limited edition
Moff's Avatar
Det ER definitivt denne måten man gjør det på, og det er akkurat dette databaser er gode på - sammenlignet med å lagre ting i tekstfiler eller lignende.

Ut i fra måten du spør på, så virker det for meg som om du kanskje ikke har vært borti JOIN-statements i SQL før. Det man i praksis gjør når man har en felles kolonne i flere tabeller er at man skriver en JOIN-statement som sammenslår de aktuelle tabellene til én. Denne sammenslåingen gjøres kun "virtuelt" i selve spørringen, ikke "fysisk" i databasen.

Jeg kan hente ut alle venner i ett steg:

Kode

SELECT v.Navn FROM Venner AS v
INNER JOIN RegissørVenner AS rv ON rv.FK_VennerID = v.VennerID
INNER JOIN Regissører AS r ON r.RegissørID = rv.FK_RegissørID
INNER JOIN FilmRegissører AS fr ON fr.FK_RegissørID = r.RegissørID
INNER JOIN Filmer AS f ON f.FilmID = fr.FK_FilmID
WHERE f.Tittel = 'Lost In Translation'
ORDER BY v.Navn
Som du sier så er dette kanskje et litt søkt eksempel, og derfor blir også spørringen vanvittig lang - men som du ser er det et helt tydelig mønster her. Finn kolonnen som er delt mellom to tabeller og gjør en JOIN på dem. Jeg bruker aliaser her for å korte ned navnet på tabellene, slik at man også tydeligere kan se hva som er hva (dette er det AS som gjør, men du kan også omgå selve nøkkelordet "AS" hvis du vil skrive det enda kortere).

I dette eksempelet bruker jeg en INNER JOIN, en av mange ulike typer joins. Jeg bruker dette her som referansedokument når jeg skriver JOIN-statements, det er en veldig hendig jukselapp:
https://blog.codinghorror.com/a-visu...-of-sql-joins/

En annen ting du bør se på er om databasen din støtter "foreign keys". Dette er en fiffig indeks-type som gjør at du tar slike felles-kolonner et steg videre, og knytter tabellene enda tettere sammen. Med foreign keys kan du gjøre databehandling på en mye enklere måte. Et eksempel er at du kan slette en film fra Filmer-tabellen, og en foreign key kan da automatisk slette alle rader fra andre tabeller som er knyttet til denne spesifikke filmen. Uten foreign keys måtte du ha gjort slettingen manuelt i alle tabeller som er påvirket.
Takk for svar Moff Jeg har brukt joins, men har trodd at jeg kanskje gjør ting feil med tanke på at det virker så uoptimalt ut, sikkert bare i hodet mitt Japp, jeg bruker MySQL, og har satt opp foreign keys med cascade on update/delete.

Takker og bukker
Du har helt rett i at det av og til ikke er hensiktsmessig å lagre data i en normalisert, relasjonell database. Da kan man f.eks denormalisere tabellene, eller rett og slett benytte en annen type database enn relasjonell, f.eks key-value-store eller graf-db. Det er imidlertid viktig å huske på at en sjeldent går gjennom en tabell rad for rad. Hvis man indekserer en kolonne, vil databasemotoren i snitt besøke 30 rader for å finne 1 av 1milliard rader, det skal med andre ord veldig store datamengder til før man får problemer med ytelse som ikke kan løses i en rasjonell database.
Sist endret av lor3ntz; 7. september 2017 kl. 23:54.
lor3ntz: Wow, det er imponerende! Ok skjønner, men indeksering er kanskje noe man kan ta tak i senere? Eller er dette noe man må ha i bakhodet helt fra starten?

En annen ting jeg lurer på, hva tenker dere om navngivning? Sånn som nå så har jeg kalt tabellen som skal inneholde kategorier for Kategorier, dersom jeg på et senere tidspunkt ønsker kategorier for noe annet så vil jo dette skape problemer. Jeg tenkte at jeg kunne ha kalt den FilmKategorier, men hva skal jeg isåfall kalle referansetabellen som nå har dette navnet?

Det jeg har tenkt i forhold til referansetabellene er at de heter ParentTabellChildTabell, og dette er jo greit i dette lille eksempelet, men dersom jeg endrer navn på kategorier til FilmKategorier, så blir jo referansetabellen hetende FilmFilmKategorier.

Når det gjelder navn på fields, finnes det et argument for å prefikse disse også? F.eks. om man har et field som heter "Navn" under film-tabellen, burde denne heller hete "FilmNavn"?

Og en siste ting, hva tenker dere om språk? Er det greit å ha tabellnavn o.l. på Norsk? Eller er det ansett som fy-fy?
Sist endret av stepry; 9. september 2017 kl. 16:21.
Det er klart at det kan vente til senere, men indekser kommer automatisk på primærnøkler og lager du en indeks for hver fremmednøkkel også er du ~80% på veien til en optimalisert database.

Hvis man har data fra flere flere forskjellige områder er det god praksis å lage et eget skjema for hvert område, da ville tabellene for eksempel kalles film.kategorier og film.filmer, mens en annen tabell kunne vært nettbutikk.kategorier e.l.

De to siste spm avhenger egentlig kun av preferanse - så lenge man er konsistent i navngivingen.
Sitat av lor3ntz Vis innlegg
Hvis man har data fra flere flere forskjellige områder er det god praksis å lage et eget skjema for hvert område, da ville tabellene for eksempel kalles film.kategorier og film.filmer, mens en annen tabell kunne vært nettbutikk.kategorier e.l..
Vis hele sitatet...
Aaah, så det er normalt å dele opp i skjemaer? Det høres ryddig ut, men da antar jeg at man mister muligheten til å koble tabeller mellom skjemaer sammen? Jeg har jo sett at jeg har skjemaer i MySQL Workbench, men det har ikke falt meg inn at jeg kan ha flere skjemaer i samme database

En annen ting jeg lurer på, når det gjelder å ha bilder til de forskjellige filmene, er det normalt at man lagrer URL-en til bildet i et eget field i databasen?
Sist endret av stepry; 9. september 2017 kl. 18:04. Grunn: Automatisk sammenslåing med etterfølgende innlegg.
NOOOOOOOOOOOOOOOOOO-
robhol's Avatar
Nei, man kan fortsatt JOINe tabeller i forskjellige skjemaer, men det er ikke nødvendigvis noen vits i å dele opp en database i skjemaer hvis det ikke åpenbart gjør det lettere å kategorisere ting.

Noen andre ting jeg ville anbefalt er å bruke "riktige" uttrykk innenfor domenet (mao. "sjanger", ikke "filmkategori"), og bruke engelsk heller enn norsk (både i kode, database, dokumentasjon osv.).

Bilder kan definitivt lagres eksternt og vises til med en sti/URL, men det er heller ikke uvanlig å bare lagre dem direkte i databasen som binær data. (BLOB osv.)
Sist endret av robhol; 9. september 2017 kl. 18:07.
Og en siste ting, dersom jeg ønsker å ha stikkord til forskjellige filmer, hvordan vil det være hensiktsmessig å gjøre dette? Jeg tenkte først at man bare har et field hvor man kan skrive inn stikkord separert med komma (f.eks. "fotball, matlaging, slåssing"). Men, jeg kunne også ha hatt en egen tabell som jeg linket til de forskjellige filmene, fordelen med dette vil være at jeg unngår duplicate data, så er det kanskje mer hensiktsmessig i forhold til å f.eks. liste alle filmer med et gitt stikkord?

robhol: Takk for svar Ok, men foreign keys/constraints kan man kanskje ikke ha?
Sist endret av stepry; 9. september 2017 kl. 18:10.
NOOOOOOOOOOOOOOOOOO-
robhol's Avatar
Jo. Skjemaer har ingen enorm innvirkning på hvordan ting fungerer. (Så vidt jeg vet. Dette kan godt variere kraftig fra ett db-system til et annet.)

Du vil *ikke* lagre tags kommaseparert i databasen, dette ødelegger normaliseringen og gjør både søk og endringer mye, mye mindre effektive. Tags på filmer vil definitivt være et mange-til-mange-forhold, og du trenger en "bindetabell" slik du nevner.