Vytváření relací

V této lekci se konečně dozvíte co jsou to ty relace a proč se SQL databázím říká relační databáze. Nastudováním této lekce se vaše znalosti o relačních databázích posunou na zcela novou úroveň. Bude to trochu teoretická a docela ukecaná kapitola, ale myslím že nic těžkého na pochopení.

Oprašte si znalost některých pojmů, jako jsou relace, primární klíč a cizí klíč. Budete je teď hodně potřebovat. Spojování tabulek pomocí klíčů je jedna z velkých předností (relačních) databází. V této kapitole se na příkladech pokusím vysvětlit, jak a proč se tabulky spojují.
Většina práce se spojováním tabulek je na bedrech příkazu SELECT. Tento příkaz budu probírat podrobně v dalších a dalších kapitolách, v této kapitole se zatím budu věnovat jen vytváření relací mezi tabulkami.

Příkaz SELECT jste zatím používali k vrácení obsahu celé tabulky, nebo její části – vybírali jste sloupce (jejich vyjmenováním za klíčovým slovem SELECT), nebo, pomocí podmínky WHERE, jen některé řádky. Brzo vás čeká získávání dat z více tabulek najednou jedním SELECTem.

K čemu je to dobré

Protože jste si zopakovali základní pojmy, jako je relace, primární klíč a cizí klíč, nemusím asi moc vysvětlovat.

Zatím jesm ukazoval jen návrhy jednoduché databáze, kde jsem si vystačil s jednou tabulkou o několika sloupcích. Teď si představte, že jste ve velkém podniku, kde si musíte vést záznamy o svých zaměstnancích, jak dlouho u vás pracují, kolik berou, kdy dostali prémie, co je náplní jejich práce, v jakém jsou oddělení, atd., atp. Musíte si také vést záznamy o pracovních odděleních, kolik tam pracuje lidí, jací lidé, záznamy o zakázkách, které vaše firma dostala, kdo a kdy, na zakázce pracoval, kdo jí zadal …
Nacpat to všechno do jedné tabulky je pochopitelně nepraktické, ne-li nemožné. A asi je vám už jasné, že mezi tabulkami, které navrhnete, jsou různé vztahy. Například vztahem mezi tabulkou oddělení a zaměstnanci bude třeba to, kdo pracuje v jakém oddělení, nebo třeba taky kdo šéfuje danému oddělení.

Trochu konrétněji: První tabulka bude obsahovat informace o zaměstnancích (tabulku pojmenuji zamestnanci), se sloupečky pro jméno a příjmení zaměstnance, věk, v jakém oddělení pracuje, jeho rodné číslo a cokoli vás ještě bude zajímat), v další tabulce budou informace o odděleních (tabulka oddeleni), sloupečky budou např. název oddělení, telefon do oddělení atp.).
Další tabulka by mohla obsahovat informace o zakázkách (tabulka zakazky) se sloupečky zákazník, cena zakázky, datum objednávky, datum vyhotovení zakázky, které oddělení na zakázce pracovalo atd. atd.
Ale co to povídám, žádný sloupečky o zákazníkovi v tabulce o zakázkách nebudou. Pro zákazníky si přece vytvoříte tabulku zakaznici

Proč to všechno? Abyste si v informacích udrželi pořádek. Zkuste si představit, že byste chtěli mít informace o oddělení a zaměstnancích v jedné tabulce. Každý řádek by musel obsahovat informace o zaměstanci a informace o oddělení ve kterém pracuje a taky informace o oddělení, kterému šéfuje (pokud nějakému). Sloupečků by tam bylo požehnaně a informace o odděleních zduplikované nepočítaněkrát.

Další informace o tom jak správně navrhovat tabulky a udržovat pořádek v datech se dozvíte v povídání o normalizaci databáze v nějaké příští kapitole. Teď opustím teorii a ukáži, jak se ty vztahy mezi tabulkami řeší v SQL databázi.

PRIMARY KEY

Jak vložit informace do tabulky zamestnanci o tom, ve kterém oddělení zaměstnanec pracuje? Mohli byste tam vkládat název oddělení. To má ovšem své nevýhody. Může se stát, že bude v podniku více oddělení se stejným názvem. Potom se také může název oddělení změnit a pak je třeba upravit nejen tabulku oddeleni, ale také tabulku zamestnanci a vůbec všechny tabulky, kde se na dané oddělení odkazují.

Tyto problémy se řeší pomocí primárního klíče – evidenčních čísel. Každé oddělení bude mít své jedinečné číslo a tím se všechny problémy odstraní. Toto číslo bude primárním klíčem tabulky oddeleni.

Primárním klíčem nemusí být jen číslo. Klidně by to mohl být název oddělení (pokud by byl unikátní), ale práce s čísly je mnohem rychlejší. (Zvláště proto, že se na primární klíč odkazujete z jiné tabulky toutéž hodnotou.)
Protože se do tabulky zavádí jinak nic neříkající a s oddělením nijak nesouvisející číslo, říká se mu někdy umělý klíč. To už ale zase moc terorizuju teoretizuju :-).

Sloupcové omezení PRIMARY KEY zajišťuje dvě věci. Jednak bude klíč jedinečný, a také (navíc od UNIQUE) se na tento sloupec může odkazovat z jiné tabulky (a všichni skandujeme: relace relace relace!) pomocí REFERENCES (cizího klíče). A za třetí, primární klíč nemůže být NULL :-).

Poznámka: Při vytvoření primárního klíče se vytvoří index, který DBMS používá k zajištění výše zmíněných vlastností PK.

Poznámka: tabulka může mít jenom jeden primární klíč (jen na jednom sloupci v tabulce může být integritní omezení PRIMARY KEY).

REFERENCES

REFERENCES je integritní omezení, které říká, že hodnoty ve sloupci budou primárními klíči z jiné tabulky (a z jaké tabulky). Jinak řečeno to říká, že jde o sloupec cizích klíčů (foreign keys).

Cizí klíč může být NULL (samosebou jen pokud k sloupečku nepřidáte integritní omezení NOT NULL).

Jak se takové integritní omezení zapisuje? Za klíčovým slovem REFERENCES následuje název tabulky, do které se budeme odkazovat (např. do oddeleni) a v závorce za názvem tabulky bude název sloupce s primárními klíči této tabulky:

název a typ sloupečku ... REFERENCES oddeleni (prim_klic),

Z toho vyplývá, že nejdříve musí existovat tabulka, do které se cizí klíč odkazuje. A musí mít sloupec s primárním klíčem.

Při vytvoření reference se vytvoří index.

V sloupci s cizími klíči nemusí být jedinečné hodnoty. Samosebou jen pokud nepřidáte podmínku UNIQUE. Určitě bude více zaměstnanců, kteří pracují v jednom oddělení, takže to dělat nebudu, ale jsou situace, kdy se to hodí.

Příklad

Kdybych ukazoval příklady pro jednotlivé odstavce této kapitoly, nebyly by vidět potřebné souvislosti. Všechno tedy osvětlím na jednom „velkém“ příkladu. S tímto příkladem pak budu pracovat i v dalších lekcích.

Úvod

[tabulky]

Příklad obsahuje dvě tabulky. První, oddeleni, obsahuje primární klíč s názvem prim_klic, druhá, zamestnanci, obsahuje odkaz na sloupec primárních klíčů první tabulky v sloupečku s názvem oddeleni_id.

Všiměte si, že relace mezi tabulkou zaměstnanců a oddělení neříká nic o podstatě této relace. Je zaměstnanec vedoucím daného oddělení? Nebo v něm jen pracuje? Nebo jej chodí uklízet? V tomto příkladě budu relaci považovat za relaci „zaměstanec pracuje v“.

Název prim_klic je dost ujetý název, normálně se používá pro sloupeček s primárním klíčem název id. Někdo používá název jako oddeleni_id, takže by se primární klíč v tabulce oddeleni jmenoval stejně jako v tabulce, která se na primární klíč odkazuje (třeba v tabulce zamestnanci). To ale dost prudí při JOINování tabulek (o kterém budu povídat později), takže také někteří chytráci používají název ve tvaru id_oddeleni, což považuju za nejzvrhlejší možnost :-). V zásadě je ale nejdůležitější jen jedno pravidlo: pojmenovávejte primární a cizí klíče ve všech tabulkách konzistentně (ne že jednou použijete id, pak id_tabulky, pak id_tabulka a pak tabulka_id …).

Typ SERIAL a SEQUENCE

Typ SERIAL není vlastně žádný typ. Pokud pro sloupeček použijete SERIAL, ve skutečnosti bude mít sloupeček typ INTEGER a navíc se vytvoří SEQUENCE, která se použije pro automatické vyplňování sloupečků číselnou řadou.

SEQUENCE je databázový objekt, který si pamatuje, jaké číslo „vydal“ naposledy. Můžete jí vytvořit pomocí příkazu CREATE SEQUENCE.

Sekvenci můžete požádat o další číslo v řadě explicitně, nebo můžete nastavit sloupeček, aby používal sekvenci jako svou defaultní hodnotu.

Když použijete typ SERIAL, vytvoří se sloupeček s typem INTEGER, vytvoří se sekvence a použije se u sloupečku jako defaultní hodnota. Spousta koláčů bez práce :-)

SEQUENCE se používá hlavně s primárními klíči. Když vkládáte řádek a pro primární klíč nevložíte žádnou hodnotu (použijete DEFAULT, nebo sloupeček vynecháte), primární klíč si vezme hodnotu ze sekvence. Tím je zaručeno, že každý řádek bude mít unikátní hodnotu.

Představte si, jak by to fungovalo bez sekvence. Dva uživatelé se přihlásí k databázi. Oba se ve stejný okamžik podívají, jaké je maximální ID v databázi (třeba 10). Oba se pokusí vložit řádek s ID o jedno větší (11). První uspěje, druhý selže.

Nebo jiný příklad. Někdo smaže z databáze řádek s nejvyšším ID (třeba 10). K tomuto ID se váže spousta (papírových) dokumentů. Někdo další příjde k databázi, podívá se na nejvyšší ID (které bude 9), zvýší ho o 1 a vloží řádek s ID již smazaného řádku (s ID 10). A všechny papírové dokumenty se najednou vztahují k novému řádku, který za to chudák nemůže. No a to je průs…

Doufám, že už chápete, jak jsou sekvence důležité. Někdy příště se vrátím k tomu, jak vytvářet a používat sekvence jinak, než automaticky s „typem“ SERIAL.

Vytvoření tabulek a vložení dat

Všechny SQL příkazy jsem pro vás uložil do souboru psql6.sql, abych vám ušetřil trochu psaní. (Jak jej můžete použít se dočtete v kapitole Začínáme s PostgreSQL).

Skript můžete spouštět kolikrát chcete. Vždycky vám znovu vytvoří tabulky a naplní je daty. Aby se mohli tabulky (znovu) vytvořit, nesmí v databázi existovat (před prvním spuštěním skriptu zřejmě nebudou, ale při druhém už ano). Proto se na začátku souboru psql6.sql mažou tabulky příkazem DROP TABLE IF EXISTS a stejně tak se musí smazat sekvence, které vzniknou použitím datového typu SERIAL. Indexy primárních klíčů a referencí se smažou automaticky při smazání tabulky, nově i sekvence, které vzniknou použitím SERIAL.

DROP TABLE IF EXISTS  zamestanci;
DROP TABLE IF EXISTS oddeleni;
DROP SEQUENCE IF EXISTS oddeleni_prim_klic_seq;

DROP SEQUENCE je s novou verzí PostgreSQL zbytečné, protože se sekvence smaže už příkazem DROP TABLE. Ale ani neuškodí :-).

Všiměnte si, že nejdříve musí být smazaná tabulka zamestnanci, která se odkazuje do tabulky oddeleni. Nemůžete smazat tabulku oddeleni, když se na ní nějaká jiná tabulka odkazuje. Jinak by takový odkaz odkazoval do nikam a tím by se porušila integrita databáze.

Následuje vytvoření tabulky oddeleni, která bude obsahovat jen název oddělení, telefon do daného oddělení a primární klíč se jménem prim_klic.

Postgres od verze 9.3 nezobrazí NOTICE (viz příklad níže), pokud nemá nastaven log level na DEBUG1.

rimmer1=> CREATE TABLE oddeleni (
    nazev VARCHAR(20),
    telefon VARCHAR(20),
    prim_klic SERIAL NOT NULL PRIMARY KEY
);
NOTICE:  CREATE TABLE will create implicit sequence "oddeleni_prim_klic_seq" for serial column
"oddeleni.prim_klic"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "oddeleni_pkey" for table
"oddeleni"
CREATE TABLE

Možná Vás napadlo, že byste mohli použít jako primární klíč pro tabulku oddělení telefonní číslo. Možné to je, ale mohli by nastat problémy v případě přečíslování. Všechny dokumenty, všechny odkazy, cokoliv co se vztahuje k primárnímu klíči byste museli změnit. Navíc je telefonní číslo zbytečně dlouhé (těžko budete mít v podniku milión oddělení), takže práce s ním by byla pomalejší než s umělým primárním klíčem. To jsou všechno věci, které musíte při návrhu tabulek brát v úvahu. Mezi vašimi úkoly je i (kvalifikované) věštění budoucnosti (jak moc se databáze může rozrůst)!

Druhá tabulka, zamestnanci, bude obsahovat jméno a příjmení zaměstnance, jeho plat, taktéž primární klíč (rodné číslo) a referenci do oddělení, ve kterém zaměstnanec pracuje, oddeleni_id.

Sloupec oddeleni_id tabulky zamestnanci se odkazuje do tabulky oddeleni. Proto je nutné vytvořit nejdříve tabulku oddeleni a až pak tabulku zamestnanci.

Tabulka zamestnanci využívá rodné číslo jako svůj primární klíč, ale to teď není podstatné.

rimmer1=> CREATE TABLE zamestnanci (
    jmeno VARCHAR(20),
    prijmeni VARCHAR(20),
    plat INTEGER CHECK (plat >= 0),
    oddeleni_id INTEGER REFERENCES oddeleni(prim_klic),
    rodne_cislo CHAR(10) NOT NULL PRIMARY KEY
);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "zamestnanci_pkey" for table
"zamestnanci"
CREATE TABLE

Teď už můžete vkládat data. Zase platí, že nejdříve se musí vložit data do tabulky s primárním klíčem a až pak do tabulky (tabulek), které se na tento primární klíč odkazují. Nemůžete vložit do tabulky zaměstnanců záznam s odkazem na neexistující řádek v tabulce oddělení.

Tohle není zbytečná buzerace, naopak, je to způsob, jak zajistit integritu dat, jak snížit možnost chyb. (Je lepší zaznamenat chybu už při vkládání dat do databáze, než aby vám DBMS umožnil vložit chybné data a přišlo se na to náhodou někdy za pár měsíců). Nikdo vás nemůže nutit primární klíče a refence používat, mohli byste používat prostě sloupečky typu INT bez integritních omezení a pak byste mohli mazat i vytvářet tabulky v libovolném pořadí, vkládat a mazat data v libovolném pořadí, ale přišli byste o tuto důležitou kontrolu. (Obdobně by se to dalo napsat o dalších integritních omezeních, jako je UNIQUE, NOT NULL, CHECK). Jejich použití je dobrovolné, ale velice, velice doporučované (všude tam, kde dávají smysl).

Příklad:

INSERT INTO oddeleni(nazev, telefon, prim_klic) VALUES ('Sekretariat', '2 123 123 12', DEFAULT);
INSERT INTO oddeleni(nazev, telefon) VALUES ('Pravni oddeleni', '2 123 123 11');
INSERT INTO oddeleni(nazev, telefon) VALUES ('Pravni oddeleni', '2 123 123 13');

Přišel čas vložit do databáze záznamy o zaměstnancích. Čísla primárních klíčů jednotlivých oddělení jsou (díky sekvenci) postupně 1, 2 a 3. Přesvědčit se o tom můžete příkazem SELECT.

Pokud se pokusíte vložit do tabulky záznam s již existujícím primárním klíčem (v případě tabulky zaměstnanců se stejným rodným číslem), nepodaří se vám to (p.k. je UNIQUE). Stejně tak, pokud se pokusíte vložit záznam s cizím klíčem, který neexistuje v tabulce do které se cizí klíč odkazuje (v případě tabulky zaměstnanců je cizý klíč číslo oddělení).

INSERT INTO zamestnanci VALUES ('Lenka',  'Pavova',10000,1,'8001010601');
INSERT INTO zamestnanci VALUES ('Jana',   'Pavova',10000,1,'8001010602');
INSERT INTO zamestnanci VALUES ('Jana',   'Mala',  12000,1,'8001010603');
INSERT INTO zamestnanci VALUES ('Lenka',  'Pavova',15000,2,'8001010604');
INSERT INTO zamestnanci VALUES ('Tom',    'Jerry', 15000,2,'8001010605');
INSERT INTO zamestnanci VALUES ('Martin', 'Luter', 12000,2,'8001010606');
INSERT INTO zamestnanci VALUES ('Leopold','King',  13000,2,'8001010607');
INSERT INTO zamestnanci VALUES ('Tomas',  'Mann',  22000,3,'8001010608');
INSERT INTO zamestnanci VALUES ('Vasek',  'Trn',   16000,3,'8001010609');
INSERT INTO zamestnanci VALUES ('Stary',  'Osel',   9000,3,'8001010610');

Teď už nemůžete smazat žádný záznam z tabulky oddělení, protože na každou řádku se odkazuje nějaký řádek z tabulky zaměstnanců. Pokud byste chtěli oddělení smazat, musíte nejdříve „přesunout“ zaměstnance do jiného oddělení (změnit jejich oddeleni_id), nebo je vyhodit :-).

rimmer=> DELETE FROM oddeleni WHERE prim_klic = 1;
ERROR:  update or delete on table "oddeleni" violates foreign key constraint "zamestnanci_oddeleni_id_fkey"
on table "zamestnanci"
DETAIL:  Key (prim_klic)=(1) is still referenced from table "zamestnanci".

Tabulky z této kapitoly budu používat pro výklad v dalších kapitolách.

Proč relační databáze

Už víte z čeho je název relační databáze odvozen? Ne, nevíte :-P. Relační databáze totiž nemají nic společného s relacemi, které jsem popisoval v této kapitole (ač si to hodně lidí myslí). Existují i relační databáze, které takovéto relace nepodporují.

Termín relace přišel z matematiky, z teorie množin. Relací je myšlena samotná tabulka, která je vlastně podmnožinou kartézkého součinu množin všech přípustných hodnot všech sloupců – což je relace.

Řádky tabulky jsou záznamy, které mají atributy ve formě sloupečků. Představte si tabulku, která by obsahovala všechny záznamy všech možných kombinací atributů – to je kartézký součin. Tabulka ale obsahuje většinou jen některé (smysluplné) záznamy, tedy relace.

Schválně se zeptejte svého učitele databází, jestli ví, proč se relačním databázím říká relační. Nejspíš to vědět bude (doufám), ale vy se aspoň blýsknete, že to víte taky :-).

MySQL

Všechny SQL příkazy jsem pro vás uložil do souboru psql6-mysql.sql.

Co se teorie primárních klíčů, referencí a integritních omezení týče, to platí pro všechny databáze stejně. Jak je to uděláno prakticky, to už je jiná káva.

Předně, MySQL nemá, nezná a neumí SEQUENCE. Místo toho můžete na sloupečku s primárním klíčem přidat tzv. AUTO_INCREMENT, který dělá v podstatě to samé jako sekvence. (V MySQL nemůžete sekvence vytvářet sami (třeba pro jiné sloupečky, které nejsou primární klíče), mazat je atd. MySQL prostě databázový objekt SEQUENCE nezná).

Za další je pro MySQL důležité, abyste použili ENGINE InnoDB. Jinak MySQL nebude kontrolovat vztah mezi primárním a cizým klíčem (můžete vložit cizý klíč, který odkazuje na neexistující primární klíč atd.)

CREATE TABLE oddeleni (
        nazev VARCHAR(20),
        telefon VARCHAR(20),
        prim_klic INT NOT NULL PRIMARY KEY AUTO_INCREMENT
) ENGINE=InnoDB;

A ještě jeden chyták v MySQL. Pokud vytvoříte tabulku takto:

CREATE TABLE zamestnanci (
    jmeno VARCHAR(20),
    prijmeni VARCHAR(20),
    plat INTEGER CHECK (plat >= 0),
    oddeleni_id INTEGER REFERENCES oddeleni(prim_klic),
    rodne_cislo CHAR(10) NOT NULL PRIMARY KEY
) ENGINE=InnoDB;

Tak jednak nebude fungovat CHECK (ten nefunguje v MySQL nikdy, jak už víte), ale ani REFERENCES. Proč ne? To fakt nevím. Ale naštěstí existuje alternativní zápis integritního omezení (constraintu) REFERENCES, který už v MySQL (s engine InnoDB) funguje:

CREATE TABLE zamestnanci (
    jmeno VARCHAR(20),
    prijmeni VARCHAR(20),
    plat INTEGER CHECK (plat >= 0),
    oddeleni_id INTEGER,
    rodne_cislo CHAR(10) NOT NULL PRIMARY KEY,
    FOREIGN KEY (oddeleni_id) REFERENCES oddeleni(prim_klic)
) ENGINE=InnoDB;

Prvnímu způsobu zápisu se říká definice na úrovni sloupce, druhému definice na úrovni tabulky. První v MySQL nefunguje (je ignorován), druhý funguje. Druhý způsob zápisu funguje i v PostgreSQL.

K čemu je vůbec dobrý druhý způsob zápisu? Možná už jsem se zmínil, že primární klíč se může skládat z více sloupců. V takovém případě jej nelze definovat na úrovni sloupečku. Taktéž cizí klíč, který se odkazuje na více sloupečků (na primární klíč skládající se z více sloupečků) se musí definovat na úrovni tabulky. Proto jsou za klíčovými slovy FOREIGN KEY sloupce, které tvoří cizí klíč, uzavřené v závorkách (a oddělené čárkou, když jich je více).

V příkladu nahoře se skládá cizí klíč jen z jednoho sloupce (oddeleni_id), ale i tak musí být uzavřen v závorkách. Pamatujte si to!

SQLite

Všechny SQL příkazy jsem pro vás uložil do souboru psql6-sqlite.sql.

SQLite také nezná sekvence. Umožní vám sice vytvořit tabulku s typem SERIAL, ale to je jen synonymum pro INTEGER. SQLite má, podobně jako MySQL, AUTOINCREMENT (na rozdíl od MySQL se píše bez podtržítka).

AUTOINCREMENT se dá použít jen s primárním klíčem nad sloupečkem s datovým typem INTEGER (kupodivu s jeho synonymem INT to nejde.)

CREATE TABLE oddeleni (
        nazev VARCHAR(20),
        telefon VARCHAR(20),
        prim_klic INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT
);

Jak už jsem psal dříve, SQLite neumí použít při insertu DEFAULT, takže první INSERT do tabulky oddělení, kde jsem jeho použití schválně ukázal, fungovat v SQLite nebude (tak ho musíte přepsat jako následující dva INSERTy z příkladu).

V SQLite můžete definovat REFERENCES jak na úrovni sloupce, tak na úrovni tabulky, oboje bude fungovat. (Hanbi sa, MySQL!).

SQLite cizí klíče defaultně nepodporuje. Kontrolu cizích klíčů musíte zapnout následujícím příkazem:

PRAGMA foreign_keys = ON;

Samozřejmě to znamená určité spomalení práce, ale integrita dat je určitě důležitější. Doporučuji vám tento příkaz zapsat do ~/.sqliterc, aby se vám kontrola cizích klíčů zapínala automaticky.

Oracle

Všechny SQL příkazy jsem pro vás uložil do souboru psql6oracle.sql. (Poznámka: v Apexu si musíte nahrát soubor pod jménem „psql6oracle“ nebo tak nějak. Název nemůže obsahovat nic jiného než písmena a čísla (takže ani tečku, ani „mínus“)).

Oracle tentokrát moc nepotěší. Sice má sekvence, ale nemá „typ“ SERIAL, takže si sekvence musíte vytvořit explicitně. Ale co hůř, nemůžete hodnotu ze sekvence použít jako defaultní hodnotu pro sloupeček. Musíte jí tak předávat při každém insertu.

Oracle také neumí klauzuli IF EXISTS, takže se na to musí přes programování.

BEGIN
   EXECUTE IMMEDIATE 'DROP TABLE zamestnanci';
EXCEPTION
   WHEN OTHERS THEN
      IF SQLCODE != -942 THEN
         RAISE;
      END IF;
END;
/

O co tu jde? Program začíná slovem BEGIN, pak se spustí okamžitě SQL příkaz DROP TABLE zamestnanci (který v uvozovkách nesmíte ukončovat středníkem). Pak se zachytí jakákoliv výjimka (exception), ke které dojde a zkontroluje se její číselný kód. Kód -942 odpovídá chybě mazání tabulky, která neexistuje. Když se nejedná o tento kód, výjimka se znovu vyvolá (RAISE), když se jedná o tento kód, neudělá se nic (chyba se tiše ignoruje).

Celý program se pak ukončí lomítkem /.

Pokud spustíte program bez závěrečného lomítka v Apexu v okně "SQL Commands", tak vám to projde. Ale běda vám, pokud byste na něj zapoměli ve skriptu!

O programování v Oracle by se dala napsat celá kniha, to tady popisovat nebudu. Berte proto prosím předchozí (a následující) příklad jako dogma.

Totéž platí při mazání sekvence, jen kód výjimky je jiný: -2289.

BEGIN
   EXECUTE IMMEDIATE 'DROP SEQUENCE oddeleni_prim_klic_seq';
EXCEPTION
   WHEN OTHERS THEN
      IF SQLCODE != -2289 THEN
         RAISE;
      END IF;
END;
/

Tabulka oddeleni se vytvoří s typem INTEGER pro primární klíč a sekvence se vytvoří následne SQL příkazem CREATE SEQUENCE. Na vytváření tabulky zamestnanci už není nic zajímavého.

CREATE TABLE oddeleni (
        nazev VARCHAR2(20),
        telefon VARCHAR2(20),
        prim_klic INTEGER NOT NULL PRIMARY KEY
);

CREATE SEQUENCE oddeleni_prim_klic_seq;

CREATE TABLE zamestnanci (
        jmeno VARCHAR2(20),
        prijmeni VARCHAR2(20),
        plat INTEGER CHECK (plat >= 0),
        oddeleni_id INTEGER REFERENCES oddeleni(prim_klic),
        rodne_cislo CHAR(10) NOT NULL PRIMARY KEY
);

Zajímavé jsou ještě příkazy pro vložení dat do tabulky oddeleni. Protože prim_klic nemá defaultní hodnotu, musí se při insertu vkládat explicitně. Další hodnota v řadě se ze sekvence získá pomocí NEXTVAL.

INSERT INTO oddeleni(nazev, telefon, prim_klic) VALUES
    ('Sekretariat','2 123 123 12', oddeleni_prim_klic_seq.NEXTVAL);
INSERT INTO oddeleni(nazev, telefon, prim_klic) VALUES
    ('Pravni oddeleni','2 123 123 11', oddeleni_prim_klic_seq.NEXTVAL);
INSERT INTO oddeleni(nazev, telefon, prim_klic) VALUES
    ('Pravni oddeleni','2 123 123 13', oddeleni_prim_klic_seq.NEXTVAL);

Na vkládání do tabulky zamestnanci už nic zajímavého není.

Komentář Hlášení chyby
Created: 11.9.2005
Last updated: 9.9.2015
Tato stánka používá ke svému běhu cookies, díky kterým je možné monitorovat, co tu provádíte (ne že bych to bez cookies nezvládl). Také vás tu bude špehovat google analytics. Jestli si myslíte, že je to problém, vypněte si cookies ve vašem prohlížeči, nebo odejděte a už se nevracejte :-). Prohlížením tohoto webu souhlasíte s používáním cookies. Dozvědět se více..