J. Macur, FAST VUT, 2011 (kombinované studium BU04)
ČísloJménoDruhVýběhPlochaŽereKolikOšetřovatelMzda 23SkippyKlokanU vchodu500Seno10Novák Jan BrumlaMedvědNa skalách300Maliny50Lom Karel KulíkVombatU vchodu500Tráva5Novák Jan JanaMedvědNa skalách300Maliny50Lom Karel Při provozu zjistíme, že potřebujeme ještě: vybavenost každého výběhu datum narození a odměny ošetřovatelů seznam nemocí, kterými zvířata trpí... U každého exempláře druhu Medvěd bude stejná hodnota atributu stravování, stejné hodnoty plochy výběhu u zvířat žijících společně, stejná mzda u zvířat, které ošetřuje Novák – datová redundance + riziko nekonzistence Řešení: normalizace databáze (vytvoření více tabulek spojených klíči)
Master tabulka Zvíře idjmenodruh_idvybeh_idOsetrovatel_id 23Skippy Brumla Kulík Jana iddruhzerekolikchoroby 15KlokanSeno10Zánět kapsy 8MedvědMaliny50Upadnutí ucha 45VombatTráva5Lenost... Druh (slave tabulka) idjmenoprijmenimzdaodmena 18JanNovák KarelLom Osetrovatel Vybeh idnazevplochavybaveni 32U vchodu500Domeček 14Na skalách300Bazén... Primární klíč (Primary Key) Cizí klíč (Foreign Key) The key, the whole key, and nothing but the key, so help me Codd
ZvířeVýběh Druh Ošetřovatel Kardinalita vztahu Kardinalita M : N (síťový model) 1 : N (hierarchický model) 1 : 1 (relační model)
ZvířeOšetřovatel ZvířeOšetřovatelZvíře_Ošetř M : N O každé zvíře se může starat více ošetřovatelů Dva cizí klíčeJen primární klíč
ZvířeVýběh Druh Kardinalita vztahu Ošetřovatel Zvíře_Ošetř
SELECT jmeno FROM zvire WHERE vybeh_id = 34 SELECT jmeno, prijmeni, mzda FROM osetrovatel WHERE mzda>10000 ORDER BY prijmeni Výstupem příkazu je relace (výstupní množina) – možnost řetězení za klauzulí FROM
Potřebné informace se v jedné tabulce nevyskytují Používaná syntaxe SELECT zvire.jmeno FROM zvire INNER JOIN zvire_osetrovatel ON zvire_osetrovatel.zvire_id = zvire.id INNER JOIN osetrovatel ON zvire_osetrovatel.osetrovatel_id = osetrovatel.id WHERE osetrovatel.prijmeni = ‘Novotný‘
Klasická syntaxe SELECT zvire.jmeno FROM zvire, zvire_osetrovatel, osetrovatel WHERE osetrovatel.prijmeni = ‘Novotný‘ AND osetrovatel.id = zvire_osetrovatel.osetrovatel _id AND zvire.id = zvire_osetrovatel.zvire_id
Seznam zvířat s názvem druhu pro konkrétní výběh SELECT zvire.jmeno, druh.nazev AS druh FROM zvire INNER JOIN druh ON zvire.druh_id = druh.id WHERE zvire.vybeh_id = 3 Pokud však definujeme výběh podmínkou (nepřímo), potřebujeme další tabulku: SELECT zvire.jmeno, druh.nazev AS druh FROM zvire INNER JOIN druh ON zvire.druh_id = druh.id INNER JOIN vybeh ON zvire.vybeh_id = vybeh.id WHERE vybeh.plocha > 1000
Častá technika – použijeme tutéž tabulku s jiným názvem. Dále pracujeme jako v případě dvou tabulek. Které páry zvířat druhu 5 žijí pohromadě (ve stejném výběhu)? SELECT zvire.jmeno, zvire1.jmeno, zvire.vybeh_id FROM zvire INNER JOIN zvire AS zvire1 ON zvire.vybeh_id = zvire1.vybeh_id WHERE druh_id = 5 AND zvire.id > zvire1.id Poslední část podmínky eliminuje obsahově stejné záznamy s alternovaným pořadím zvířat a logický fakt, že každé zvíře žije samo se sebou.
Hodnota NULL (neznámá, nedefinovaná) je další možný výsledek logického výrazu V relačních výrazech je v takovém případě výsledek vždy NULL (a=4, b=NULL, a>b vrací NULL) podmínka (hodnota=NULL) vrací NULL i v případě, že hodnota obsahuje NULL, musíme použít oeprátory IS NULL a IS NOT NULL V logických spojeních OR, AND, XOR s hodnotou NULL je výsledek vždy NULL
Používáme v případech potřeby zahrnutí záznamů ve spojených tabulkách, kdy ve druhé tabulce neexistuje partnerský záznam. Vyhledáme zvířata, která jsou ve výběhu sama: SELECT zvire.jmeno, zvire.vybeh_id FROM zvire LEFT OUTER JOIN zvire AS zvire1 ON zvire.vybeh_id = zvire1.vybeh_id AND zvire.id<zvire1.id WHERE zvire1.id IS NULL Alternativní řešení (viz dále) SELECT zvire.jmeno, zvire.vybeh_id FROM zvire WHERE zvire.vybeh_id IN (SELECT vybeh_id FROM zvire GROUP BY vybeh_id HAVING count(*)=1)
SELECT zvire.jmeno, vybeh.nazev FROM zvire LEFT OUTER JOIN vybeh ON vybeh.id = zvire.vybeh_id INNER JOIN druh ON zvire.druh_id = druh.id WHERE druh.nazev = ‘Ježura’ V případě vnitřního spojení bychom nedostali záznamy o zvířatech, která žijí volně (nemají výběh)
SELECT id,COUNT(*) AS pocet FROM zvire INNER JOIN vybeh ON zvire.vybeh_id=vybeh.id WHERE vybeh.plocha>100 SELECT SUM(mzda) AS naklady FROM osetrovatel WHERE gender=1 SELECT AVG(plocha) AS prum_plocha FROM vybeh
Pomocí klauzule GROUP BY Relace je setříděna podle atributu a rozdělena na skupiny, v kterých má atribut odlišnou hodnotu Na záznamy ve skupině je obvykle aplikován agregační výraz Vzniklá relace může obsahovat pouze atributy: Agregáty pro skupinu Identifikační atribut skupiny uvedený v GROUP BY Tvorbu skupin lze provádět i pomocí více atributů než jednoho (skupina prvního atributu rozdělena na více podskupin podle hodnot druhého atributu)
SELECT vybeh_id, COUNT(*) AS pocet FROM zvire INNER JOIN vybeh ON zvire.vybeh_id=vybeh.id WHERE zvire.druh_id=5 GROUP BY vybeh_id ORDER BY pocet Smysl má pouze výsledné uspořádání. Před seskupením lze aplikovat standardní restrikci. Výstupní restrikce po seskupení pomocí klauzule HAVING
Příkaz Select vrací relaci (tabulku), která může vstoupit do dalšího spojení. Seznam zvířat s uvedením počtu jedinců ve výběhu pro případ, že počet jedinců je více než 5. SELECT jmeno, pocet FROM zvire INNER JOIN SELECT vybeh_id, count(*) as pocet FROM zvire AS zvire1 GROUP BY vybeh_id ON zvire.vybeh_id=zvire1.vybeh WHERE pocet > 5
Jednoprvková množina příkazu Select může stát na místě atributu. Příkaz uvede ke každému zvířeti měrnou plochu ve výběhu (celkovou plochu dělenou počtem jedinů) SELECT jmeno, (SELECT plocha FROM vybeh WHERE vybeh.id=zvire.vybeh_id)/(SELECT count(*) from zvire AS zvire1 WHERE zvire1.vybeh_id=zvire.vybeh_id) AS mernaPlocha FROM zvire ORDER BY mernaPlocha
Jiné použití jednoprvkového výstupu příkazu Select. Seznam zvířat s nadprůměrnou cenou: SELECT zvire.jmeno,druh.nazev FROM zvire INNER JOIN druh ON druh.id=zvire.druh_id WHERE cena > (SELECT AVG(cena) FROM zvire) ORDER BY cena DESC