MySQL (23) - relace 1:N a N:N

Co znamenají zkratky 1:N a N:N? Jak souvisejí se psaním spojení a proč by nestačilo mít jen jeden typ spojení? To všechno se dozvíte v dnešním díle seriálu o MySQL.

3.6.2005 07:00 | Petr Zajíc | přečteno 57432×

Zatím jsme v seriálu rozebírali taková spojení, při nichž šlo o dvě tabulky. Napsal jsem ale rovněž, že principielně lze spojit i více tabulek. Ačkoli to nepředstavuje žádný syntaktický zádrhel, pro začátečníky v oblasti databází bývá někdy problém pochopit logiku takových spojení. Proto se jim dnes budeme trochu věnovat.

Spojení 1:N

Toto spojení jsme vlastně již probrali. Tajemnou zkratkou "1:N" se v databázovém světě rozumí spojení, kde jeden záznam v "hlavní" tabulce obsahuje teoreticky libovolný počet odpovídajících záznamů v "podřízené" tabulce. (Teoreticky libovolný počet zahrnuje rovněž nulu). Připomeňme také, že k vyjádření takového spojení se používá:

V praxi existuje celá řada situací, na níž lze toto schéma uplatnit. Pro osvěžení si některá připomeňme:

Celá situace se dá poměrně snadno znázornit graficky. Na obrázku níže můžete vidět, jak by vyladalo spojení mezi tabulkou faktur a jejich položek.

Kdybychom něco takového chtěli zapsat pomocí SQL, nebude to problém:

select * from faktury join polozky on faktury.id = polozky.faktura;

Spojení N:N

Co je špatného na modelu 1:N, že potřebujeme vymyšlet něco dalšího? Na modelu samotném není špatného nic. Problém spočívá v tom, že pro reálný svět tento model zkrátka nepostačuje. Vraťme se na chvíli k naší imaginární databázové aplikaci, která má mapovat provoz v knihovně. Jak byste zmapovali proces půjčování knih? Je pravda, že jeden čtenář si může půjčit více knih, ALE zároveň je pravda, že více čtenářů si může půjčit stejnou knihu (dejme tomu v různém období). Vztah mezi knihami a čtenáři tedy není 1:N, ale N:N.

Realizovat něco takového pomocí dvou tabulek v reálné databázi většinou nejde. Takový vztah se obyčejně programuje pomocí další, třetí tabulky, která je spojena s oběma původními tabulkami. S každou tabulkou má vztah 1:N a celé to dokáže simulovat spojení N:N. Protože se to asi dá jen těžko představit, posloužím zase malým obrázkem:

Je dobré si "prostřední" tabulku nějak smysluplně nazvat, i když to někdy nebude tak úplně jednoduché. My bychom si ji mohli nazvat například "výpůjčky". Z toho je krásně vidět, jak je relace N:N "rozbita" na dvě relace 1:N. Platí totiž:

V praxi to často bývá tak, že "prostřední" tabulka neslouží pouze jako technický prostředek k realizaci spojení N:N, ale že obsahuje i nějaké smysluplné informace. Například si dokážu představit, že by tabulka výpůjček docela dobře mohla obsahovat datum půjčení a datum vrácení každé publikace. To totiž nepatří logicky ani do tabulky knih, ani do tabulky čtenářů.

Pozn.: Vidíte mimochodem, jak nesmírně je toto řešení pružné? Umožňuje například postihnout situaci, kdy čtenář nevrátí všechny knihy, které má půjčené ve stejném termínu. Protože pro každou kombinaci kniha-čtenář existuje řádek v tabulce výpůjček, lze to pohodlně zapsat.

V praxi bychom tedy mohli pomocí výše uvedené průpravy například sestavit seznam právě vypůjčených knih:

select knihy.nazev, ctenari.prijmeni from
knihy join vypujcky on knihy.id = vypujcky.kniha
join ctenari on vypujcky.ctenar = ctenari.id
where vypujcky.vracenodne is null;

Poznámky ke spojením

Zejména spojení N:N vyžadují určitou představivost ze strany programátora. Během let, kdy jsem programoval databázové aplikace, jsem si sestavil několik tipů, které se vám možná také budou hodit:

Online verze článku: http://www.linuxsoft.cz/article.php?id_article=854