IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

9. diel - Oracle krok za krokom: Otázky cez viac tabuliek (JOIN)

V minulej lekcii, Oracle krok za krokom: Dátové typy a NULL , sme si ukázali dátové typy a vysvetlili hodnotu NULL.

Dnes začneme robiť na jednoduchom redakčnom systéme, ktorý môže pripomínať ten tu na ITnetwork. Ukážeme si dopytovania cez viac tabuliek.

Konceptuálny model

V nasledujúcich dieloch si teda v databáze vytvoríme taký zjednodušený ITnetwork. Pobavte sa najprv o tom, ako to bude vyzerať. Dnes stihneme pochopiteľne len malú časť. Pretože obrázok niekedy povie viac, ako tisíc slov, začnime práve ním.

Konceptuálny model redakčného systému - Oracle

Čo vidíte je tzv. Konceptuálne model. Je vytvorený pomocou notácie (grafického jazyka) UML a v praxi sa takéto diagramy veľmi často tvoria predtým, než začneme písať nejaký kód. Dobre si tak najprv rozmyslíme, čo že to vlastne chceme urobiť.

Vidíme, že v systéme figuruje užívateľ, ktorý môže písať komentáre a články. Články spadajú do sekcií. Jedná sa teda o databáze takého veľmi jednoduchého redakčného systému, ktorý si vďaka ITnetwork iste dokážete predstaviť.

Príprava tabuliek a dát

Dnes sa zameriame na otázky cez viac tabuliek. Poďme si najprv nejaké tabuľky vytvoriť. Bohato nám budú stačiť užívatelia a články.

Užívatelia

Pretože užívateľ bude vyzerať trochu inak, než nám vyzeral doteraz, založíme si tabuľku uzivatele znova. Tú súčasnú teda dropneme:

DROP TABLE uzivatele;

Následne vytvoríme tabuľku novú. Užívateľ tu bude mať (okrem id) prezývku, mail a heslo:

CREATE TABLE uzivatele (
    uzivatele_id INT GENERATED ALWAYS AS IDENTITY (START with 1 INCREMENT by 1),
    prezdivka VARCHAR2(155),
    email VARCHAR2(155),
    heslo VARCHAR2(255),
    PRIMARY KEY (uzivatele_id)
);

Do užívateľov si rovno nejaké vložíme:

INSERT INTO uzivatele (prezdivka, email, heslo)
WITH zaznamy AS
(
    SELECT 'Míša', '[email protected]', 'dGg#@$DetA53d'   FROM dual UNION ALL
    SELECT 'David', '[email protected]', '$#fdfgfHBKBKS'     FROM dual UNION ALL
    SELECT 'Denny', '[email protected]', 'Jmls_aSW2RFss'        FROM dual UNION ALL
    SELECT 'Emma', '[email protected]', 'fw8QT32qmcsld'           FROM dual
)
SELECT * FROM zaznamy;

Články

Článok bude prepojený s užívateľom, ktorý ho napísal, teda s jeho autorom. Tabuľky prepojíme tak, že do tabuľky clanky pridáme stĺpec s id autora. Tam bude hodnota id užívateľa (teda primárny kľúč z tabuľky uzivatele), ktorý článok napísal.

Hovoríme o väzbe 1: N (1 používateľ má N (niekoľko) článkov a každý článok patrí práve jednému používateľovi). Časť (tu článok) má vždy uložené id celku (tu užívateľ) kam patrí.

Článok bude obsahovať (opäť okrem svojho id) ID autora, krátky popis, URL, kľúčové slová, titulok, obsah a dátum publikácie. Založme si tabuľku clanky:

CREATE TABLE clanky (
    clanky_id INT GENERATED ALWAYS AS IDENTITY (START with 1 INCREMENT by 1),
    autor_id INT,
    popis VARCHAR2(155),
    url VARCHAR2(155),
    klicova_slova VARCHAR2(155),
    titulek VARCHAR2(155),
    obsah VARCHAR2(4000),
    publikovano DATE,
    PRIMARY KEY (clanky_id)
);

Všimnime si, že stĺpec obsah má dátový typ VARCHAR2(4000), čo je v Oracle štandardná maximálna dĺžka VARCHAR2. Keby sme chceli tento limit navýšiť, museli by sme nastaviť parameter MAX_STRING_SIZE na EXTENDED.

Ďalej pridáme články ak nim priradíme používateľa ako autormi. Vzal som 4 články tu z ITnetwork, ktoré som značne skrátil a zjednodušil. Otázka bude nasledujúci:

INSERT INTO clanky (autor_id, popis, url, klicova_slova, titulek, obsah, publikovano)
WITH zaznamy AS
    (
        SELECT 1, 'Co je to algoritmus? Pokud to nevíte, přečtěte si tento článek.', 'co-je-to-algoritmus', 'algoritmus, co je to, vysvětlení', 'Algoritmus', 'Když se bavíme o algoritmech, pojďme se tedy shodnout na tom, co ten algoritmus vůbec je. Jednoduše řečeno, algoritmus je návod k řešení nějakého problému. Když se na to podíváme z lidského pohledu, algoritmus by mohl být třeba návod, jak ráno vstát. I když to zní jednoduše, je to docela problém. Počítače jsou totiž stroje a ty nemyslí. Musíme tedy dopodrobna popsat všechny kroky algoritmu. Tím se dostáváme k první vlastnosti algoritmu - musí být elementární (skládat se z konečného počtu jednoduchých a snadno srozumitelných kroků, tedy příkazů). "Vstaň z postele" určitě není algoritmus. "Otevři oči, sundej peřinu, posaň se, dej nohy na zem a stoupni si" - to už zní docela podrobně a jednalo by se tedy o pravý algoritmus. My se však budeme pohybovat v IT, takže budeme řešit problémy jako seřaď prvky podle velikosti nebo vyhledej prvek podle jeho obsahu. To jsou totiž 2 základní úlohy, které počítače dělají nejčastěji a které je potřeba dokonale promýšlet a optimalizovat, aby trvaly co nejkratší dobu. Z dalších příkladů algoritmů mě napadá třeba vyřeš kvadratickou rovnici nebo vyřeš sudoku.', '21.3.2012' FROM dual UNION ALL
        SELECT 2, 'Bakterie jsou obdoba buněčného automatu v kombinaci s hrou.', 'bakterie-bunecny-automat', 'bakterie, automat, algoritmus', 'Bakterie', 'Bakterie jsou obdoba buněčného automatu, který vymyslel britský matematik John Horton Conway v roce 1970. Celou tuto hru řídí čtyři jednoduchá pravidla:/n/n
        1. Živá bakterie s méně, než dvěma živými sousedy umírá./n
        2. Živá bakterie s více, než třemi živými sousedy umírá na přemnožení./n
        3. Živá bakterie s dvoumi nebo třemi sousedy přežívá beze změny do další generace./n
        4. Mrtvá bakterie, s přesně třemi živými sousedy, opět ožívá./n
        Tyto zdánlivě naprosto primitivní pravidla dokáží za správného počátečního rozmístění bakterií vytvořit pochodující skupinky, shluky "vystřelující" pochodující pětice, překvapivě složité souměrné exploze, oscilátory (periodicky kmitající skupinky), či nekonečnou podívanou na to, jak složité a dokonalé obrazce dokáží tyto dvě podmínky vytvořit. Celý program je koncipován jako hra, máte za úkol vytvořit co nejdéle žijící kolonii. <a href="soubory/bakterie.zip" ', '14.2.2012' FROM dual UNION ALL
        SELECT 3, 'Cheese Mouse je oddechová plošinovka.', 'cheese-mouse-oddechova-plosinovka', 'myš, sýr, hra', 'Cheese Mouse', 'Cheese mouse je plošinovka s "horkou ostrovní atmosférou", kde ovládáte myš a musíte se dostat k sýru. V tom vám ale brání nejrůznější nástrahy a nepřatelé jako hadi, krysy, pirane, ale i roboti, mumie a nejrůznější havěť. Hru s několika petrobarevnými světy jsem dělal ještě na základní škole s Veisenem a může se pochlubit 2. místem v Bonusweb game competition, kde vyhrála 5.000 Kč. Vznikala v Game makeru o letních prázdninách, ještě v bezstarostném dětství, což značně ovlivnilo její grafickou stránku. Rád si ji občas zahraji na odreagování a zlepšní nálady. <a href="soubory/cheesemouse.zip" />', '22.6.2004' FROM dual UNION ALL
        SELECT 2, 'Pacman je remake kultovní hry.', 'pacman-remake', 'pacman, remake, pampuch, hra, zdarma', 'Pacman', 'Jedná se o naprosto základní verzi této hry s editorem levelů, takže si můžete vytvořit svá vlastní kola. Postupem času ji hodlám ještě trochu upravit a přidat nějaké nové prvky, fullscreen a lepší grafiku. Engine hry bude také základem mého nového projektu Geckon man, který je zatím ve fázi psaní scénáře. <a href="soubory/pacman.zip" />', '3.6.2011' FROM dual
    )
SELECT * FROM zaznamy;

Ak na vás vyskočí hláška "Enter value for ...", žiadnu hodnotu nezadávajte, a klikajte iba na OK. Táto hláška ide vypnúť príkazom SET DEFINE OFF.

Otázky cez viac tabuliek

Teraz máme v databáze články ak nim priradené užívateľa. Poďme si urobiť dotaz cez tieto 2 tabuľky, získajte články ak nim pripojme prezývky ich užívateľov. Slovo pripojme som nepoužil náhodou, príkaz pre spojenie 2 tabuliek sa totiž volá JOIN. Napíšme si otázku a potom si ho vysvetlíme. Otázky už budeme písať na viac riadkov, aby sme sa v tom vyznali.

SELECT titulek, prezdivka
FROM clanky
JOIN uzivatele ON autor_id = uzivatele_id
ORDER BY prezdivka;

výsledok:

TITULOK prezývky
baktérie David
pacman David
Cheese Mouse Denny
algoritmus Míša
Na prvom riadku príkaze SELECT pracujeme so stĺpci úplne rovnako, ako keby boli v jednej tabuľke, jednoducho vymenujeme, čo nás zaujíma. Keďže vyberáme články ak nim pripájame užívateľa, budeme vyberať z tabuľky clanky. Pripojenie dát z inej tabuľky urobíme pomocou príkazu JOIN, kde uvedieme tabuľku, ktorú pripájame, a potom klauzulu ON. Klauzula ON je podobná ako WHERE, len platí pre pripojenú tabuľku a nie pre tú, z ktorej primárne vyberáme. V podmienke uvedieme, aby sa ku každému článku pripojil ten užívateľ, ktorého uzivatele_id je uvedené v stĺpci autor_id. Výsledok sme zoradili podľa prezývky užívateľov. Keby sme chceli len nejaké články, normálne by sme pred ORDER BY uviedli ešte WHERE, ako sme zvyknutí.

INNER JOIN a OUTER JOIN

INNER (vnútorná) a OUTER (vonkajšie) JOIN sú 2 typy príkazu JOIN. Fungujú úplne rovnako, jediný rozdiel je v tom, čo sa stane, keď položka, na ktorú sa väzba odkazuje, neexistuje.

INNER JOIN

Ak uvedieme v SQL dotaze len JOIN, pokladá ho Oracle databázy za tzv. INNER JOIN. Ak by v našom prípade neexistoval užívateľ s id, ktoré je u článku uvedené, článok bez užívateľa by vôbec nebol vo výsledkoch obsiahnutý. Väzba je nerozdeliteľná.

Poďme si to skúsiť, pridajme si článok, ktorý bude odkazovať na id neexistujúceho užívateľa:

INSERT INTO clanky (autor_id, popis, url, klicova_slova, titulek, obsah, publikovano) VALUES
(99, 'Článek s neexistujím uživatelem slouží pro vyzkoušení typů JOINů.', 'clanek-bez-autora', 'clanek, join, autor, chybejici', 'Článek bez autora', 'Tento článek je přiřazen neexistujícímu uživateli s ID 99 a slouží k vyzkoušení různých typů JOINů v MySQL databázi.', '21.10.2012');

Vložený článok sa odvoláva na užívateľov s uzivatele_id 99, ktorý v databáze nie je. Spustite si teraz znovu náš SQL dotaz s JOIN. Pre prehľadnosť je lepšie uviesť, že chceme INNER JOIN:

SELECT titulek, prezdivka
FROM clanky
INNER JOIN uzivatele ON autor_id = uzivatele_id
ORDER BY prezdivka;

výsledok:

TITULOK prezývky
baktérie David
pacman David
Cheese Mouse Denny
algoritmus Míša
Výsledok je stále rovnaký, článok bez autora medzi výsledkami nie je.

LEFT OUTER JOIN

Vonkajšie join umožňujú vyberať aj tie výsledky, ktoré sa nepodarilo spojiť z dôvodu chýbajúcich položiek. Skúsme si tzv. LEFT JOIN, ktorý výsledok uzná, ak existuje ľavá časť väzby (tu článok) a pravá (tá pripájané, tu užívateľ) neexistuje. Do hodnôt stĺpcov z pripojovanej časti sa vloží NULL:

SELECT titulek, prezdivka
FROM clanky
LEFT JOIN uzivatele ON autor_id = uzivatele_id
ORDER BY prezdivka;

výsledok:

TITULOK prezývky
baktérie David
pacman David
Cheese Mouse Denny
algoritmus Míša
Článok bez autora (Null)
Vidíme, že článok sa rovnako vybral, aj keď sa nepodarilo vybrať pravú časť (teda tú pripojenú, používateľa). Pred spájaním tabuliek je dobré sa zamyslieť, či nastane prípad, keď sa spojenie nepodarí a čo v tom prípade chceme robiť. Pri článku by sa toto v reáli stáť asi nemalo.

RIGHT OUTER JOIN

Podobne ako ľavý vonkajší JOIN uznal väzbu v prípade, že ľavá časť existovala, pravý JOIN to urobí naopak. Pokiaľ bude existovať užívateľ (pravá, pripájané časť) a nebude k nemu existovať článok (ľavá časť), bude rovnako v tabuľke zahrnutý. Osobne som tento JOIN ešte nepoužil. V tabuľke jedného takého používateľa máme, je ním používateľ Emma. Oracle ešte naviac pre RIGHT JOIN vyžaduje použitie kľúčového slovíčka OUTER, ktoré by sme mohli uviesť aj za LEFT JOIN, tam to ale nie je vyžadované. Skúsme si teda RIGHT OUTER JOIN:

SELECT titulek, prezdivka
FROM clanky
RIGHT OUTER JOIN uzivatele ON autor_id = uzivatele_id
ORDER BY prezdivka;

výsledok:

TITULOK prezývky
pacman David
baktérie David
Cheese Mouse Denny
(Null) Emma
algoritmus Míša
Podľa očakávaní zmizol Článok bez autora a objavila sa Ema.

Ešte nejaké join by sme určite v Oracle našli, ale pre naše účely nám toto bohato stačí.

Wherování

Teoreticky sa môžeme JOINům vyhýbať a používať namiesto nich jednoducho len klauzulu FROM a WHERE. Vo FROM uvedieme viac tabuliek oddelených čiarkami. Vo WHERE špecifikujeme podmienku spojenie tabuliek. Databáza si v ideálnom prípade takýto dotaz najprv prevedie na INNER JOIN a potom ho spracuje:

SELECT titulek, prezdivka
FROM clanky, uzivatele
WHERE autor_id = uzivatele_id
ORDER BY prezdivka;

Výsledok je teda rovnaký ako pri INNER JOIN:

TITULOK prezývky
baktérie David
pacman David
Cheese Mouse Denny
algoritmus Míša
Nevýhoda wherování je, že tak neurobíme všetky join a v určitých prípadoch môžu byť otázky menej optimalizované. Nikdy nevieme, ako dotaz databázy optimalizuje a optimalizácia sa bude líšiť podľa typu databázy. Tento spôsob berte skôr ako zaujímavosť a nepoužívajte ho.

V ďalšej lekcii, Oracle krok za krokom: Ďalšie otázky a väzba M: N , si precvičíme dopytovania cez viac tabuliek, pozrieme sa bližšie na väzbu M: N, a vysvetlíme si, čo je to väzobné tabuľka.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 11x (2.79 kB)
Aplikácia je vrátane zdrojových kódov

 

Predchádzajúci článok
Oracle krok za krokom: Dátové typy a NULL
Všetky články v sekcii
Oracle
Preskočiť článok
(neodporúčame)
Oracle krok za krokom: Ďalšie otázky a väzba M: N
Článok pre vás napísal Matěj Kadlec
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se programování věnuje od střední školy, nyní studuje informatiku na VŠB-TUO a pracuje jako ETL developer pro společnost IDC. Mezi jeho oblíbené jazyky patří Python a SQL.
Aktivity