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.
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;
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;
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: