Kapcsolótáblák és SQL
Sziasztok!
Elnézést, ha triviális a kérdés, de nem találom a megoldást. Adatmodell szinten, ha létezik egy Személy és egy Zenei stílus egyedtípusom, akkor azt a kapcsolatot, hogy mely személyek mely zenei stílusokat kedvelnek, a két egyedtípus közötti M:N kapcsolattal, vagyis kapcsolótáblával fejezhetek ki. Vagyis van egy Személyek táblám: (id, név, egyéb adatok), egy Zenei stílusok táblám (id, név, egyéb adatok) és egy Személyek_Zenei stílusok kapcsolótáblám (id, személy_id, zenei_stílus_id, esetleges további adatok). Ugyanakkor SQL szinten sok dokumentációban olvashatok JOIN-okról, beágyazott SELECT-ekről, többtáblás lekérdezésekről stb. Csak arra nem találok példát, hogy hogyan kérdezhetném le a fenti példát felhasználva például azt, hogy kik milyen zenei stílusokat kedvelnek. Összefoglalhatnánk, hogy az adatmodellezésben használható 1:N és M:N, valamint rekurzív kapcsolattípusok hogyan valósulnak meg SQL szinten?
■ Elnézést, ha triviális a kérdés, de nem találom a megoldást. Adatmodell szinten, ha létezik egy Személy és egy Zenei stílus egyedtípusom, akkor azt a kapcsolatot, hogy mely személyek mely zenei stílusokat kedvelnek, a két egyedtípus közötti M:N kapcsolattal, vagyis kapcsolótáblával fejezhetek ki. Vagyis van egy Személyek táblám: (id, név, egyéb adatok), egy Zenei stílusok táblám (id, név, egyéb adatok) és egy Személyek_Zenei stílusok kapcsolótáblám (id, személy_id, zenei_stílus_id, esetleges további adatok). Ugyanakkor SQL szinten sok dokumentációban olvashatok JOIN-okról, beágyazott SELECT-ekről, többtáblás lekérdezésekről stb. Csak arra nem találok példát, hogy hogyan kérdezhetném le a fenti példát felhasználva például azt, hogy kik milyen zenei stílusokat kedvelnek. Összefoglalhatnánk, hogy az adatmodellezésben használható 1:N és M:N, valamint rekurzív kapcsolattípusok hogyan valósulnak meg SQL szinten?
Mit szeretnél?
Ajjaj...
Az első LEFT JOIN által szolgáltatott találati halmaz szerepel a második LEFT JOIN bal oldalán táblaként?
Válasz
SELECT *
FROM (szemelyek LEFT JOIN szemelyek_zenei ON szemelyek.id=szemelyek_zenei.szemely)
LEFT JOIN zeneistilus ON zeneistilus.id=szemelyek_zenei.zenei;
Az MS Access esetén szükséges kitenni a zárójeleket, a többi adatbázskezelőnél nem szükséges, de nem is hiba.
Ha a kapcsolat rekurzív
Buta vagyok, nem értem...
Hibaüzenet
Megfogadtam a tanácsot ;)
Ha a baratok táblában a szemely_id Klári azonosítóját, míg a barat_id Béla azonosítóját tartalmazza és futtatom a következő lekérdezést (nagyjából vbence javaslatával azonos):
a.) vagy a lekérdezésben
b.) vagy a táblaszerkezetekben?
Vagy PHP-ből kell megoldani, hogy amikor mentjük az adatbázisba a Klári barátja Béla viszonyt, akkor egyidejűleg rögzíteni kell a Béla barátja Klári viszonyt is?
Barátság modellezése
Amit ajánlok:
kapcsolat (id, kezdemenyezo_szemely, targy_szemely, ido, status)
ismeretseg (id, alany_szemely, targy_szemely, csoport)
Egy baráságot 3 rekord testesítene meg: a kapcsolat táblában egy, ami tartalmazhatja a "bejelölés" körülményeit, valamint, hogy visszaigazolt baráságról van-e szó. Az ismeretseg táblában pedig 2 reord lenne: az egyik és másik szereplő nézetéből. Így lehetőségünk van hogy a tagok csoportokba sorolják barátaikat.
A törlést lehet triggerrel megoldnai, vagy kézzel. Írhatóak teszt-lekérdezések is, amik ellenőrizni tudják az adatok konzisztenicáját.
Inkább általánosítsunk
Mindamellett gyanús nekem az ajánlatodban a kezdemenyezo_szemely-targy_szemely, illetve alany_szemely-targy_szemely pár ismétlődése. Merthogy a kezdeményező=alany (csak a kapcsolat táblában kicsit speciális az alany szerepe). Nem? Vagyis miért nem egy tábla az a kettő?
És ahogy írod:
aminek személyek esetén lehet is értelme, hiszen nem mindegy ki a meghívó (bejelölő) fél és ki a másik. Már logikai szinten is különbözik a két fél. Ám, ha nem érdekel minket a különbség? Úgy tűnik mindenképp kényszerítve vagyunk a megkülönböztetésre: ismeretseg (id, egyik_fél, másik_fél, ...), hiszen egy táblában nem lehet két mező neve azonos. Hogyan lehet ezt a kényszert elfedni a lekérdezéssel?
UI.: Két dolog jutott eszembe:
Egyrészt, Halassy B. azt írja az adatmodellezésről szóló könyvében: valójában (a relációs modell szintjén) nincs egyenrangú M:N kapcsolat, hiszen egy M:N kapcsolatot két hierarchikus 1:N kapcsolattal valósítunk meg (egyik_fél:kapcsolótábla, másik_fél:kapcsolótábla. A rekurzív kapcsolat speciális, mert egyik_fél=másik_fél, de ez nem érinti a lényeget).
Másrészt, a való életben talán tényleg nincs teljesen szimmetrikus viszony a két fél között. Mint ahogy a személyek esetén mindenképp érdekelni fog minket, hogy ki a meghívó, zöldségek esetén talán azt a tényt szeretnénk jelezni az adatbázisban, hogy egy jó szomszédi kapcsolatban melyik fél védi a másikat annak kártevőitől (ritka, hogy ez teljesen kölcsönös).
Egyenrangú kapcsolat vs. aspektusok tárolása
Például: az uborkának mindenképpen kedvezni akarunk még azon az áron is, hogy a mellé ültetett másodlagos zöldésgnek nem feltétlenül előnyös a kapcsolat. Mondjuk, hogy az uborka mission-critical, a második zöldség pedig csak egy addicionális termék. Másik esetben a föld maximális kihasználására optimalizálunk, és azt keressük, hogy mindkét növénynek jó legyen, olyankor a kölcsönösen előnyös kapcsolatokat keressük...
Az első felére válaszolva: egy teljesen egyenrangú kapcsolatot modellezhetünk egyetlen táblával is az alábbi módon:
resztvevo (id, kapcsolat_id, szemely_id)
Itt csoportokat képzünk. Az azonos kapcsolat_id fogja összekapcsolni az összetartozó személyeket. Az id mező csak kényelmi célokat szolgál, elhegyható: lehet a (kapcsolat_id, szemely_id) egy összetett kulcs. A kapcsolat_id annyiban számít, hogy egyértelmű legyen az egyes kapcsoaltokra (barátságokra). Belátható, hogy nem szükséges külön kapcsolat táblának lennie, csak gondoskodnunk kell róla, hogy egyedi azonosítókat képezzünk az egyes barátságok felvitelénél.
Mindazonáltal a lekérdezések fogják meghatározni az optimális adatszerkezetet. Nem mindig a legnormalizáltabb a legjobb. Legyen ez akár cache-elés (vagyis redundancia) a gyorsabb kiszolgálás érdekében...
Ez tetszik :)
Nagyon jó! Mellesleg egy kapcsolathoz tartozhat kettőnél több személy is (a zeller szeretheti a kelkáposzta, a karalábé, a brokkoli és a paradicsom társaságát is). Hát persze: nem a Személyek egyed van M:N kapcsolatban önmagával, hanem a Személyek és a Kapcsolatok egyed (és ha az utóbbiról nem akarunk nyilvántartani semmit, akkor nem is kell mint önálló tábla).
Köszi!