====================================================================== - zdroje: - Jaroslav Pokorný, Ivan Halaška: Databázové systémy, Vybrané kapitoly a cvičení, skriptá, Karolinum, Praha 1998 - help k DB2 ====================================================================== 4. Jazyk SQL ====================================================================== ---------------------------------------------------------------------- 4.1 Úvod ---------------------------------------------------------------------- - história - v roku 1974 vznikol dopytovací jazyk Sequel (Structured English QUEry Language) bol súčasťou Systému R vyvinutého v laboratóriu IBM v San José (zamestnávateľ autora relačného modelu dát E. F. Codda); po úprave koncepcie a zjednodušení mena na SQL (structured query language) sa stal základom prvých významnejších databázových produktov DB2, SQL/DS a QMF od IBM - s nástupom PC v 80. rokoch sa mnoho svetových výrobcov software-u začalo orientovať na implementáciu SQL, od jednopoužívateľských sa postupne prechádzalo na databázové servery založené na SQL - v roku 1986 nastal zlom - štandardizácia SQL organizáciou ANSI (pod názvom SQL86), v roku 1987 bola táto štandardizácia prijatá organizáciou ISO; štandard bol dialekt SQL firmy IBM a bol charakterizovaný ako "prienik existujúcich implementácií" - v roku 1989 sa jazyk rozšíril o možnosť definovať integritné obmedzenia, táto verzia sa volá SQL89 - ďalší vývoj vyústil v roku 1992 do štandardu SQL92, ktorý ešte doteraz nie je úplne implementovaný - ďalšie štandardy - X/OPEN SQL súvisí s použitím UNIX-u ako implementačného prostredia - SAA-SQL (Systems Application Architecture Database Interface) - vlastný štandard firmy IBM - rysy modelovania dát pomocou SQL - SQL je neprocedurálny jazyk (popisuje, čo požadujeme od databázy, nie to, ako to treba urobiť) - dáta sú vždy prezentované používateľovi ako tabuľky, bez ohľadu na ich vnútornú štruktúru použitú v databáze - poloha tabuliek v databáze nie je dôležitá, sú identifikované menom - poradie stĺpcov v tabuľke nie je dôležité, sú identifikované menom - poradie riadkov v tabuľke nie je dôležité, sú identifikované hodnotami v stĺpcoch - použitie SQL - dopytovací a manipulačný jazyk pre relačné databázy - zložka hostiteľského jazyka na programovanie databázových aplikácií (embedded SQL) - jazyk komunikácie medzi rôznymi zdrojmi dát - budeme sa zaoberať SQL vo verzii DB2 ---------------------------------------------------------------------- 4.2 Definícia dát - metadáta ---------------------------------------------------------------------- - (niektoré) dátové typy - presné numerické typy - celé čísla - INTEGER (alebo INT) - 4 byte - SMALLINT - 2 byte - BIGINT - 8 byte - desatinné čísla - DECIMAL (alebo DEC) alebo NUMERIC (alebo NUM) (počet cifier [, počet desatinných miest]) - aproximatívne numerické typy - reálne čísla - FLOAT alebo FLOAT(presnosť) - REAL - pevná presnosť (daná implementáciou) - DOUBLE (alebo DOUBLE PRECISION) - pevná presnosť (dvojnásobná než pri REAL) - znakové reťazce - CHARACTER (alebo CHAR) (počet znakov) - kratší reťazec doplnený prázdnymi znakmi - počet znakov do 254 (prečo nie 256?) - CHARACTER VARYING (alebo VARCHAR) (maximálny počet znakov) - kratší reťazec nie je doplnený prázdnymi znakmi - počet znakov do 32 672 - veľké údaje (loby (z angl. large objects)) - BLOB (veľkosť (v B)) alebo (veľkosť K alebo M alebo G) - binárne - CLOB (veľkosť (v B)) alebo (veľkosť K alebo M alebo G) - reťazcové - časové údaje - DATE - dátum - spravidla v tvare YYYY-MM-DD, ale povolené je aj D.M.YYYY (alebo CURRENT DATE) - TIME - čas - v tvare HH:MM:SS (alebo CURRENT TIME) - TIMESTAMP - časová pečiatka (dátum a čas) - v tvare YYYY-MM-DD HH:MM:SS alebo YYYY-MM-DD HH:MM:SS.mmmmmm (alebo CURRENT TIMESTAMP) - linky na dáta uložené mimo databázy - DATALINK - práca s tabuľkou - vytvorenie tabuľky - príkaz CREATE TABLE - syntax (časť): CREATE TABLE meno_tabuľky (zoznam_prvkov_tabuľky) zoznam_prvkov_tabuľky ::= prvok_tabuľky [, prvok_tabuľky] prvok_tabuľky ::= definícia_stĺpca | definícia_IO_tabuľky definícia_stĺpca ::= meno_stĺpca dátový_typ [IO_stĺpca] - IO (integritné obmedzenia) stĺpca - NOT NULL - stĺpec nesmie mať prázdnu hodnotu (NULL) - DEFAULT - implicitná hodnota stĺpca - UNIQUE - všetky hodnoty v stĺpci musia byť jedinečné (NULL hodnota neprekáža) - PRIMARY KEY - stĺpec je súčasťou primárneho kľúča tabuľky - FOREIGN KEY - stĺpec je cudzí kľúč definujúci referenčnú integritu s inou tabuľkou - CHECK - zadaný logický výraz definuje integritné obmedzenie - všetky IO sa môžu definovať aj na úrovni tabuľky; nutné je to vtedy, keď sú IO kladené na viacero stĺpcov - príklady - CREATE TABLE student1 ( meno VARCHAR(10), priezvisko VARCHAR(20) ); - CREATE TABLE student2 ( id INTEGER NOT NULL, meno VARCHAR(10) NOT NULL, priezvisko VARCHAR(20) NOT NULL, datum_nar DATE NOT NULL, PRIMARY KEY (id) ); - id je primárnym kľúčom - CREATE TABLE student3 ( id INTEGER NOT NULL, meno VARCHAR(10) NOT NULL, priezvisko VARCHAR(20) NOT NULL, datum_nar DATE NOT NULL, pohlavie CHAR(4) NOT NULL CHECK (pohlavie IN ('muz', 'zena')), rodne_cislo CHAR(10) NOT NULL UNIQUE, id_mesto INTEGER, PRIMARY KEY (id), CONSTRAINT FK_mesto FOREIGN KEY (id_mesto) REFERENCES mesto, CONSTRAINT nie_kratke CHECK ((LENGTH(meno) > 1) AND (LENGTH(priezvisko) > 1)) ); - pohlavie môže nadobúdať iba hodnoty 'muz' a 'zena' - aj keď rodné číslo nie je primárnym kľúčom, nemôže nadobúdať dve rovnaké hodnoty - obmedzenie FK_mesto znamená, že stĺpec id_mesto môže nadobúdať iba hodnoty existujúce v tabuľke mesto (a tá musí tiež, samozrejme, existovať) alebo prázdnu hodnotu - obmedzenie nie_kratke znamená, že sa do databázy nedajú vložiť záznamy, ktorých by hodnoty stĺpcov meno alebo priezvisko nemali aspoň dva znaky - CREATE TABLE osoba1 ( id INTEGER, priezvisko VARCHAR(10) DEFAULT ); - po vložení záznamu iba s id sa do stĺpca meno uloží hodnota '' (prázdny reťazec) - CREATE TABLE osoba2 ( id INTEGER, priezvisko VARCHAR(10) DEFAULT 'Kovac' ); - po vložení záznamu iba s id sa do stĺpca meno uloží hodnota 'Kovac' - tabuľku možno vytvoriť aj pomocou príkazu SELECT (podrobnosti o ňom budú nižšie) - CREATE TABLE student3_kopia AS ( SELECT * FROM student3 ) DEFINITION ONLY; - úprava štruktúry existujúcej tabuľky - príkaz ALTER TABLE - syntax (časť): ALTER TABLE meno_tabuľky zmena - zmeny - pridanie stĺpca - ADD definícia_stĺpca - po pridaní stĺpca sa všetkým záznamom v tomot stĺpci priradí hodnota NULL (ak nie je určené inak) - pridanie IO tabuľky - ADD CONSTRAINT definícia_IO_tabuľky - zrušenie IO tabuľky - DROP CONSTRAINT meno_IO_tabuľky - príklady - CREATE TABLE student ( id INTEGER NOT NULL, meno VARCHAR(10), priezvisko VARCHAR(20), datum_nar DATE, id_mesto INTEGER, PRIMARY KEY (id) ); CREATE TABLE mesto ( id INTEGER NOT NULL, nazov VARCHAR(20), PRIMARY KEY (id) ); - vytvorenie cudzieho kľúča - väzby medzi dvoma existujúcimi tabuľkami - 3 možnosti vzhľadom na delete - s obmedzeným delete-om (záznam, ktorý je aspoň raz odkazovaný, potom nemožno vymazať) - ALTER TABLE student ADD FOREIGN KEY sm (id_mesto) REFERENCES mesto; (alebo alternatívne ALTER TABLE student ADD CONSTRAINT sm FOREIGN KEY (id_mesto) REFERENCES mesto;) - toto je defaultná možnosť - s kaskádnym delete-om (záznam, ktorý je aspoň raz odkazovaný, možno vymazať, ale iba vtedy, ak s ním možno vymazať aj všetky záznamy, ktoré naň odkazujú) - ALTER TABLE student ADD FOREIGN KEY sm (id_mesto) REFERENCES mesto ON DELETE CASCADE ; - v prípade úspechu môže nastať celá kaskáda delete-ov, treba byť preto pri používaní tejto možnosti opatrný - so SET-NULL delete-om (záznam, ktorý je aspoň raz odkazovaný, možno vymazať, ale iba vtedy, ak všetky hodnoty, ktoré naň odkazujú, možno nastaviť na NULL (t.j. nie sú NOT NULL)) - ALTER TABLE student ADD FOREIGN KEY sm (id_mesto) REFERENCES mesto ON DELETE SET NULL; - príklad - ak tabuľka student obsahuje záznamy (1, ..., 1), (2, ..., 2), (3, ..., 1) a tabuľka mesto o.i. záznam (1, 'Košice'), pri kaskádnom delete-e sa pri vymazaní Košíc vymažú aj záznamy (1, ..., 1) a (3, ..., 1); v prípade obmedzeného delete-u sú Košice nevymazateľné a v prípade SET NULL sa hodnoty stĺpca id_mesto v záznamoch (1, ..., 1) a (3, ..., 1) zmenia na NULL - cudzí kľúč môže odkazovať aj na stĺpec, ktorý nie je primárnym kľúčom, ten však musí byť jednoznačný (UNIQUE) - pridanie obmedzenia - ALTER TABLE student ADD CONSTRAINT dk CHECK (YEAR(datum_nar)>=2000); - zrušenie obmedzenia - ALTER TABLE student DROP CONSTRAINT dk; - pridanie nového stĺpca - ALTER TABLE student ADD COLUMN rocnik INTEGER; - ALTER TABLE student ADD COLUMN rocnik INTEGER NOT NULL; - nesprávne - nie je ho čím naplniť, prázdnu hodnotu sme práve zakázali - ALTER TABLE student ADD COLUMN rocnik INTEGER NOT NULL DEFAULT 1; - všetky doterajšie záznamy budú mať v tomto stĺpci hodnotu 1 - zrušenie tabuľky - príkaz DROP TABLE - syntax: DROP TABLE meno_tabuľky - s vymazaním tabuľky sa vymažú aj všetky jej integritné obmedzenia i tie cudzie kľúče iných tabuliek, ktoré na ňu odkazujú - príklad - pri vymazaní tabuľky mesto sa automaticky vymaže jej primárny kľúč, ale aj cudzí kľúč tabuľky student, ktorý na ňu odkazoval - indexy - index slúži na efektívnejšie vyhľadávanie záznamov, nemôže však byť súčasťou dopytu - optimalizátor vyhodnocovania dopytu sám rozhodne, či a ktorý index použije - index možno definovať pre jeden alebo kombináciu stĺpcov (pre také, ktoré sa často vyskytujú v podmienkach dopytov) - pre jednu tabuľku môže byť definovaný ľubovoľný počet indexov, mená indexov musia byť rôzne - indexy sú spravidla implementované pomocou B-stromov - vytvorenie indexu - syntax (časť): CREATE [UNIQUE] INDEX meno_indexu ON meno_tabuľky (meno_stĺpca [ASC | DESC] [, meno_stĺpca [ASC | DESC]]) [CLUSTER] - ASC resp. DESC - vzostupné resp. zostupné usporiadanie - UNIQUE - všetky hodnoty v stĺpci musia byť jedinečné (NULL hodnota neprekáža) - CLUSTER - záznamy sú v implementácii zoradené podľa neho, ležia na disku fyzicky za sebou - iba jeden z indexov môže byť CLUSTER - s pribúdajúcimi riadkami sa však správanie takejto štruktúry zhoršuje - príklad - CREATE UNIQUE INDEX pm ON student (priezvisko, meno); - zrušenie indexu - syntax: DROP INDEX meno_indexu - zrušením indexu sa nezrušia dáta - pohľady (views) - pohľad možno považovať za virtuálnu tabuľku, ktorá nemá vlastné dáta, slúži iba ako filter na dáta v iných tabuľkách; so zmenou dát v pôvodných tabuľkách sa tak automaticky mení aj výsledok pohľadu - pôvodná tabuľka, možno obsahujúca citlivé dáta, môže byť bežnému používateľovi ako celok neprístupná, pohľadom mu však možno sprístupniť aspoň jej zverejniteľnú časť - vytvorenie pohľadu - syntax (časť): CREATE VIEW meno_pohľadu [(meno_stĺpca [, meno_stĺpca]])] AS príkaz_SELECT - príkaz SELECT bude popísaný v ďalšej kapitole - zoznam mien stĺpcov a ich dátových typov je určený príkazom SELECT; ak sa mená stĺpcov z definujúceho príkazu SELECT nedajú odvodiť, zoznam mien stĺpcov pohľadu je povinný - príklady (využívame tabuľky student a mesto definované v predošlom odseku) - CREATE VIEW meno_studenta AS SELECT meno, priezvisko FROM student; - CREATE VIEW student_mesto (meno, priezvisko, mesto) AS SELECT s.meno, s.priezvisko, m.nazov FROM student s, mesto m WHERE s.id_mesto = m.id; - zrušenie pohľadu - syntax: DROP VIEW meno_pohľadu - so zrušením pohľadu sa nerušia tabuľky, na ktorých bol vybudovaný - príklad - DROP VIEW meno_studenta; - pohľady môžu byť v istých prípadoch aj aktualizovateľné - systémový katalóg - podáva informácie o metadátach - tabuľky: meno, tvorca, dátum vytvorenia, počet stĺpcov, ..., komentár - stĺpce: z ktorej tabuľky, meno, dátový typ, ..., komentár - ďalšie informácie o systéme, každý typ je v osobitnej tabuľke - pohľady, indexy, integritné obmedzenia, ..., - je zložený opäť z databázových tabuliek (presnejšie z pohľadov) a je prístupný pomocou SQL dopytov - katalóg by sa nemal dať aktualizovať bežnými aktualizačnými prostriedkami SQL, robí sa to automaticky - aktualizovať však možno komentáre k tabuľkám a stĺpcom - syntax: - pre tabuľky: COMMENT ON TABLE meno_tabuľky IS komentár_v_apostrofoch - pre stĺpce: COMMENT ON COLUMN meno_tabuľky.meno_stĺpca IS komentár_v_apostrofoch - príklady - COMMENT ON TABLE student IS 'Info o (po)riadnych studentoch'; - COMMENT ON COLUMN student.id IS 'Identifikator'; ---------------------------------------------------------------------- 4.3 Príkaz SELECT ---------------------------------------------------------------------- - SELECT-FROM-WHERE-blok (kratšie SELECT) - základný konštrukt SQL na dopytovanie (t.j. výber dát) - SELECT - klauzula obsahujúca zoznam stĺpcov výslednej tabuľky (v prípade jednoduchších mená, v prípade zložitejších ich konštrukciu), implicitne sú zahrnuté aj ich dátové typy - FROM - klauzula obsahujúca zoznam tabuliek, nad ktorými je dopyt definovaný - WHERE - klauzula obsahujúca podmienku, ktorú musia vybraté dáta spĺňať - v prípade, že táto klauzula chýba, považuje sa podmienka za tautológiu - vzťah k relačnej algebre - dopyt tvaru SELECT A_1, ..., A_j FROM R_1, ..., R_k WHERE \phi zodpovedá v relačnej algebre výrazu (R_1 x ... x R_k)(\phi)[A_1, ..., A_j] - príklady - odpoveď dopyt SELECT * FROM tabuľka je kópia tabuľky - dopyt SELECT priezvisko, nazov FROM student, mesto WHERE student.id_mesto = mesto.id zodpovedá výrazu STUDENT x MESTO (STUDENT.id_mesto = MESTO.id) [priezvisko, nazov] - v skutočnosti dopyt nemusí byť vyhodnocovaný takýmto často neefektívnym spôsobom - na rozdiel od relačnej algebry SELECT neeliminuje (automaticky) z výsledku duplicitné riadky - syntax (zjednodušená): SELECT [DISTINCT] {* | konštrukcia_stĺpca [AS alias_stĺpca] [, konštrukcia_stĺpca [AS alias_stĺpca]] | meno_tabuľky.* [, meno_tabuľky.*]} FROM meno_tabuľky [AS alias_tabuľky] [, meno_tabuľky [AS alias_tabuľky]] [WHERE podmienka] [ORDER BY špecifikácia_usporiadania_podľa_stĺpca [, špecifikácia_usporiadania_podľa_stĺpca]] - príklad - SELECT student.priezvisko, nazov AS mesto, mesto.* FROM student, mesto WHERE student.id_mesto = mesto.id ORDER BY 1 ASC, 2 DESC - konštrukcia stĺpca výslednej tabuľky je v najjednoduchšom a najčastejšom prípade meno niektorého stĺpca niektorej tabuľky z FROM klauzuly, a to v tvare meno_stĺpca alebo meno_tabuľky.meno_stĺpca resp. alias_tabuľky.meno_stĺpca - DISTINCT - eliminuje z výsledku duplicitné riadky - * znamená, že vyberáme všetky stĺpce zo všetkých tabuliek, meno_tabuľky.* znamená, že vyberáme všetky stĺpce z tabuľky meno_tabuľky - alias_stĺpca a alias_tabuľky sú lokálne premenovania (v rámci SELECTu) - mená tabuliek sa môžu opakovať, musia však potom byť odlíšené pomocou aliasov - klauzula ORDER BY presahuje rámec relačných štruktúr (tam na poradí riadkov nezáleží) - špecifikácia_usporiadania_podľa_stĺpca := [alias_stĺpca | konštrukcia_stĺpca | poradie_stĺpca] [ASC | DESC] - ASC resp. DESC - vzostupné resp. zostupné usporiadanie, implicitná hodnota je ASC - v podmienke vo WHERE možno zadať ľubovoľný booleovský výraz používajúci: - logické operátory AND (a), OR (alebo), NOT (nie) - NOT má väčšiu prioritu než AND a AND má väčšiu prioritu než OR - porovnávania (=, <> alebo !=, <, >, <=, >=) - porovnanie LIKE - umožňuje pracovať s podreťazcami hodnôt stĺpcov typu CHAR alebo VARCHAR - obvykle vo forme meno_stĺpca LIKE maska, pričom maska môže obsahovať znaky '%' (náhrada za reťazec ľubovoľnej dĺžky (aj nulovej)) a '_' (náhrada za práve jeden znak) - v maske možno použiť aj znak '%' alebo '_' - treba použiť formu meno_stĺpca LIKE maska ESCAPE iný_znak, pričom pred znakom '%' alebo '_' je v maske napísaný iný_znak - napr. vyhodnoteniu reťazca LIKE '%10@%' ESCAPE '@' vyhovuje reťazec '10%' alebo '2310%' - BETWEEN - výraz (a BETWEEN b AND c) znamená ((a >= b) AND (a <= c)) - a, b, c musia mať kompatibilné typy - IN - výraz (a IN (b_1, ..., b_n)) znamená ((a = b_1) OR ... OR (a = b_n)) - a, b_1, ..., b_n musia mať komptibilné typy - NULL (prázdnu hodnotu) - od dvojhodnotovej logiky (TRUE, FALSE) potom musíme prejsť k trojhodnotovej (naviac hodnota UNKNOWN); pre ľubovoľné porovnanie @ platí: x@y má hodnotu UNKNOWN práve vtedy, keď aspoň jedno z x a y je NULL - špeciálne aj porovnanie NULL=NULL má hodnotu UNKNOWN - pravidlá: - pre NOT: FALSE | TRUE TRUE | FALSE UNKNOWN| UNKNOWN - pre AND: | FALSE UNKNOWN TRUE -------------------------------- FALSE | FALSE FALSE FALSE UNKNOWN| FALSE UNKNOWN UNKNOWN TRUE | FALSE UNKNOWN TRUE - pre OR: | FALSE UNKNOWN TRUE -------------------------------- FALSE | FALSE UNKNOWN TRUE UNKNOWN| UNKNOWN UNKNOWN TRUE TRUE | TRUE TRUE TRUE - na porovnávanie s prázdnou hodnotou teda nemožno použiť x @ NULL; poslúžia na to porovnania x IS NULL, ktoré nadobúda hodnotu TRUE práve vtedyt, keď x je prázdna hodnota, resp. x IS NOT NULL, s ktorým je to presne naopak - príklad SELECT * FROM student WHERE cislo_izby IS NULL - študenti, ktorí nebývajú na internáte (číslo ich internátnej izby má teda prázdnu hodnotu) - vnorený SELECT - dosadí sa zaň množina, ktorá vznikne ako jeho výsledok - predikáty pre prácu s množinami - IN - príklad - SELECT * FROM student WHERE priezvisko IN (SELECT priezvisko FROM ucitel) - nájde všetkých študentov, ktorí majú menovcov medzi učiteľmi - BETWEEN - ak je použitý vnorený SELECT, jeho výsledok tu musí byť jednoznačný - príklad - SELECT * FROM student WHERE datum_nar between (SELECT MIN(datum_nar) FROM ucitel) AND (SELECT MAX(datum_nar) FROM ucitel) - nájde všetkých študentov, ktorí "sú vo veku učiteľov" - porovnávania (=, <> alebo !=, <, >, <=, >=) - ak je použitý vnorený SELECT, jeho výsledok tu musí byť jednoznačný - príklady - SELECT * FROM student WHERE datum_nar = (SELECT MAX(datum_nar) FROM student) - nájde všetkých najstarších študentov - SELECT * FROM student WHERE priezvisko = (SELECT priezvisko FROM ucitel) - nájde všetkých študentov, ktorí majú menovcov medzi učiteľmi - zafunguje iba vtedy, ak je učiteľ jediný, inak vyhodí chybu - ALL - príklad - SELECT * FROM student WHERE priezvisko <> ALL(SELECT priezvisko FROM ucitel) - nájde všetkých študentov, ktorí nemajú menovcov medzi učiteľmi - porovnanie s ALL aplikovaným na prázdnu množinu dáva TRUE - SOME (alebo aj ANY) - príklad - SELECT * FROM student WHERE priezvisko = SOME(SELECT priezvisko FROM ucitel) - nájde všetkých študentov, ktorí majú menovcov medzi učiteľmi - porovnanie so SOME aplikovaným na prázdnu množinu dáva FALSE - EXISTS, NOT EXISTS - výraz EXISTS (SELECT ...) sa vyhodnotí ako pravdivý, ak je výsledok SELECT-u v zátvorkách neprázdna množina, inak je nepravdivá - príklady - SELECT * FROM mesto WHERE EXISTS resp. NOT EXISTS ( SELECT * FROM student WHERE student.id_mesto = mesto.id ) - mestá, v ktorých býva aspoň jeden resp. nebýva žiaden študent - SELECTy môžu byť vnorené aj do viacerých úrovní - príklad - SELECT MAX(datum_nar) FROM student WHERE datum_nar < ( SELECT MAX(datum_nar) FROM student WHERE datum_nar < ( SELECT MAX(datum_nar) FROM student ) ) - dátum narodenia tretieho najstaršieho študenta - pri konštrukcii stĺpca výslednej tabuľky, ale i v termoch podmienok možno používať: - aritmetické operácie +, -, *, / - ak @ \in {+, -, *, /}, x@y má hodnotu NULL práve vtedy, keď aspoň jedno z x a y je NULL - hodnotové výrazy - hodnotový výraz vznikne kombináciou aritmetických výrazov, mien stĺpcov, agregácií, hodnôt skalárnych poddopytov (t.j. poddopytu, ktorého výsledkom je tabuľka s jedným riadkom a jedným stĺpcom) a ďalších špeciálnych funkcií, najčastejšie je to však iba meno stĺpca - príklady - SELECT (SELECT COUNT(*) FROM mesto m WHERE m.nazov <= mesto.nazov), nazov FROM mesto ORDER BY 1 - usporiadanie a očíslovanie miest podľa abecedy - SELECT MAX(datum_nar) FROM student WHERE datum_nar < ( SELECT MAX(datum_nar) FROM student ) - dátum narodenia druhého najmladšieho študenta - niektoré špeciálne funkcie - funkcie na reťazce (typu CHAR alebo VARCHAR) - LENGTH - dĺžka reťazca - príklad - LENGTH('Slovensko') = 9 - ak je prvý reťazec typu CHAR(n), funkcia LENGTH vráti n besz ohľadu na jeho (ozajstnú) dĺžku, v prípade VARCHAR sú medzery ignorované - LTRIM, RTRIM - osekáva medzery zľava, sprava - príklady - LTRIM(' Slovensko ') = 'Slovensko ' - RTRIM(' Slovensko ') = ' Slovensko' - LTRIM(RTRIM(' Slovensko ')) = 'Slovensko' - SUBSTR - vyberá z reťazca podreťazec (substring) - syntax: SUBSTR(reťazec, začiatočný_index_podreťazca, dĺžka_podreťazca) - začiatočný index reťazca je číslo znaku reťazca, to sa počíta od 1 - súčet začiatočného indexu a dĺžky podreťazca zmenšený o 1 nesmie presiahnuť dĺžku vymedzeného miesta pre reťazec - príklad - SUBSTR('Slovensko', 2, 4) = 'love' - CONCAT alebo || - konkatenuje (lepí) dva reťazce na seba - syntax: CONCAT(reťazec1, reťazec2) alebo reťazec1 || reťazec2 - príklad - CONCAT('myš', 'lienka') = 'myšlienka' - ak je prvý reťazec typu CHAR(n), ale jeho (ozajstná) dĺžka je m < n, pri lepení sa medzi reťazce vloží n-m medzier; v prípade VARCHAR sa žiadne medzery nevkladajú - UCASE, LCASE - všetky písmená zmení na veľké resp. malé - príklady - UCASE('Slovensko') = 'SLOVENSKO' - LCASE('Slovensko') = 'slovensko' - funkcie na dátumy a/alebo časovú pečiatku - YEAR - číslo roka z daného dátumu - MONTH - číslo mesiaca z daného dátumu - DAY - číslo dňa z daného dátumu - HOUR - počet hodín z danej časovej pečiatky - MINUTE - počet minút z danej časovej pečiatky - SECOND - počet sekúnd z danej časovej pečiatky - MICROSECOND - počet mikrosekúnd z danej časovej pečiatky - DAYOFWEEK - poradie dňa v týždni (nedeľa -> 1, pondelok -> 2, ...) - DAYOFYEAR - poradie dňa v roku (napr. 29.2. -> 60) - DAYS - počet dní od 1.1.1 - ďalšie užitočné funkcie - CAST - konverzia medzi typmi - syntax: CAST (výraz AS dátový_typ) - príklady - CAST (2002 AS CHAR(4)) = '2002' - CAST ('2002' AS INTEGER) = 2002 - CAST (NULL AS dátový_typ) - "všeobecný" NULL bude mať navrhnutý dátový typ - CASE - umožňuje zadať hodnotu v závislosti na hodnote nejakého stĺpca - syntax: CASE WHEN podmienka THEN výraz ... WHEN podmienka THEN výraz [ELSE výraz] END alebo CASE výraz WHEN hodnota THEN výraz ... WHEN hodnota THEN výraz [ELSE výraz] END - v prípade, že ELSE chýba, pod príslušným výrazom sa implicitne rozumie NULL - podmienky za WHEN sa nemusia vylučovať - ak ich platí viac, vezme sa prvá v poradí - ak je splnená podmienka za WHEN, vráti hodnotu výrazu za THEN; ak nie je splnená žiadna, vráti hodnotu výrazu po ELSE - príklady - SELECT priezvisko, CASE WHEN SUBSTR(rodne_cislo,3,1) IN ('0','1') THEN 'muz' WHEN SUBSTR(rodne_cislo,3,1) IN ('5','6') THEN 'zena' ELSE '???' END FROM student3; - SELECT priezvisko, CASE SUBSTR(rodne_cislo,3,1) WHEN '0' THEN 'muz' WHEN '1' THEN 'muz' WHEN '5' THEN 'zena' WHEN '6' THEN 'zena' ELSE '???' END FROM student3; - COALESCE alebo VALUE- umožňuje nahradiť NULL neprázdnym výrazom - syntax: COALESCE(V_1, ..., V_n) alebo VALUE(V_1, ..., V_n) - vráti prvú hodnotu V_i zo zoznamu, ktorá nie je NULL - príklad - COALESCE(priezvisko, meno, 'no name') dáva pre záznam ((meno, priezvisko) =) ('Albert', 'Einstein') hodnotu 'Einstein', pre ('', 'Madonna') hodnotu 'Madonna' a pre ('','') hodnotu 'no name' - NULLIF - umožňuje vrátiť prázdnu hodnotu - zápis NULLIF(V_1, V_2) je ekvivalentný zápisu CASE WHEN V_1=V_2 THEN NULL ELSE V_1 - príklad - NULLIF(tento, iny) dáva pre záznam ((tento, iny) =) (1,1) hodnotu NULL, pre záznam (1,2) hodnotu 1 - príkazy s agregačnými funkciami COUNT, SUM, MAX, MIN, AVG - agregačné funkcie sa aplikujú na časti tabuľky, ktoré vzniknú skupinovaním podľa hodnôt stĺpcov resp. z nich vytvoreného výrazu uvedeného v klauzule GROUP BY - každá skupina tak prispeje do výslednej tabuľky jedným riadkom (ak tam klauzula GROUP BY nie je, agregačná funkcia sa aplikuje na jedinú skupinu - celú tabuľku - a výsledok má jediný riadok) - významy - COUNT - počet hodnôt - SUM - suma hodnôt - MAX - maximum hodnôt - MIN - minimum hodnôt - AVG - (aritmetický) priemer hodnôt - syntax: agregačná_funkcia ([DISTINCT] hodnotový_výraz [, hodnotový_výraz]); COUNT(*) - COUNT(*) počíta všetky riadky včítane duplicít a riadkov obsahujúcich len hodnoty NULL; v iných prípadoch sú hodnoty NULL ignorované - COUNT(\empty) = 0, ale SUM(\empty) = NULL, AVG(\empty) = NULL, MIN(\empty) = NULL, MAX(\empty) = NULL - SUM a AVG možno použiť len na číselné typy - DISTINCT nezapočítava do výsledku duplicitné riadky - príklady - SELECT COUNT(*) FROM student - počet študentov - SELECT COUNT(*) FROM student WHERE (priezvisko LIKE 'P%') - počet študentov s priezviskom začínajúcim na 'P' - SELECT COUNT(DISTINCT priezvisko) FROM student - počet rôznych priezvisk študentov - SELECT MAX(datum_nar) FROM student - dátum narodenia najstaršieho študenta - klauzuly GROUP BY a HAVING - ak sa v klauzule SELECT vyskytuje aj výraz bez agregácií, musia byť uvedený v klauzule GROUP BY všetky mená stĺpcov, ktoré sa vyskytujú pri jeho konštrukcii, alebo on sám - pri použití klauzuly HAVING, ktorá je nasledovaná logickou podmienkou (ako pri WHERE), sa z tabuľky vzniknutej apolikáciou na jednotlivé skupiny vyberú len tie riadky, ktoré podmienke vyhovujú - príklad - výpis miest, z ktorých sú aspoň dvaja študenti: SELECT nazov, COUNT(*) FROM student, mesto WHERE mesto.id = student.id_mesto GROUP BY nazov HAVING COUNT(*) > 1 - podľa definície sú SUM(\empty), AVG(\empty), MAX(\empty) a MIN(\empty) rovné NULL, nie 0; v takom prípade možno namiesto výrazu agregačná_funkcia(stĺpec) použiť výraz COALESCE(agregačná_funkcia(stĺpec), 0) - pri počítaní AVG je výsledok rovnakého typu ako hodnoty, z ktorých sa priemer počíta, čo môže byť v prípade celočíselných typov zavádzajúce; v takom prípade treba celočíselné hodnoty konvertovať na desatinné čísla - príklad - v tabuľke so schémou hodnotenie(meno: INTEGER, znamka: INTEGER) nech sú hodnoty ('Jano',1), ('Mišo',2), ('Fero',3), ('Ďuro',4); dopyt SELECT AVG(znamka) FROM hodnotenie dáva celočíselnú hodnotu 2, ale správna hodnota je 2.5; dosiahneme ju dopytom SELECT AVG(CAST (znamka AS DECIMAL(5,2))) FROM hodnotenie - spojenia tabuliek - v klasickom SELECT príkaze SELECT A_1, ..., A_j FROM R_1, ..., R_k WHERE \phi je \phi spravidla konjunkciou podmienok dvoch typov - jednak sú tu väzobné podmienky medzi zúčastnenými tabuľkami R_1, ..., R_k a jednak porovnania s konštantami; SQL umožňuje tieto dva typy podmienok oddeliť tým, že väzobné podmienky sa definujú už v klauzule FROM, a to (napríklad) v takejto forme ekvivalentnej s predošlou: SELECT A_1, ..., A_j FROM R_1 JOIN R_2 ON väzobné_podmienky_medzi_R_1_A_R_2 ... JOIN R_k ON väzobné_podmienky_medzi_R_i_A_R_k WHERE ostatné podmienky - príklad - dopyt na všetky informácie o všetkých študentoch s menom Jozef SELECT * FROM student s, mesto m, skupina g, izba i, typ_izby t WHERE s.id_mesto = m.id AND s.id_skupina = g.id AND s.id_izba = i.id AND i.id_typ = t.id AND s.meno = 'Jozef' možno ekvivalentne nahradiť dopyotm SELECT * FROM student s JOIN mesto m ON s.id_mesto = m.id JOIN skupina g ON s.id_skupina = g.id JOIN izba i ON s.id_izba = i.id JOIN typ_izby t ON i.id_typ = t.id WHERE s.meno = 'Jozef' - možné sú aj kombinácie týchto prístupov - časť väzobných podmienok je v kluzule FROM pod JOIN-mi, zvyšok je vo WHERE klauzule - príklad - ďalším ekvivalentným zápisom k predošlým dvom je napr. dopyt SELECT * FROM student s JOIN mesto m ON s.id_mesto = m.id JOIN skupina g ON s.id_skupina = g.id JOIN izba i ON s.id_izba = i.id, typ_izby t WHERE i.id_typ = t.id AND s.meno = 'Jozef' - spojenia tabuliek a prázdne hodnoty - pri použití obyčajného spojenia sa (podľa definície) eliminujú riadky, v ktorých je hodnota niektorého prepájacieho stĺpca prázdna; niekedy je však vhodné mať vo výsledku aj riadky s prázdnymi hodnotami ako zdôraznený signál toho, že na nich nemožno nič naviazať; v takomto prípade namiesto obyčajného spojenia použijeme tzv. vonkajšie spojenie - typy vonkajšieho spojenia - ľavé vonkajšie spojenie - R_1 LEFT OUTER JOIN R_2 - do výsledku sa okrem záznamov, za ktoré "môže" obyčajný JOIN, pridajú aj tie záznamy pochádzajúce z R_1, ktoré nemajú partnerov v R_2, pričom miesta stĺpcov z R_2 sú doplnené prázdnymi hodnotami - pravé vonkajšie spojenie - R_1 RIGHT OUTER JOIN R_2 - úlohy R_1 a R_2 sa vymenia - úplné vonkajšie spojenie - R_1 FULL OUTER JOIN R_2 - výsledkom je zjednotenie ľavého a pravého vonkajšieho spojenia - na zdôraznenie odlišnosti od vonkajších spojení sa obyčajnému spojeniu hovorí aj vnútorné spojenie (a namiesto JOIN možno použiť INNER JOIN) - syntax: - na mieste, kde by sa vo vnútornom spojení napísalo JOIN, tu sa napíše LEFT OUTER JOIN resp. RIGHT OUTER JOIN resp. FULL OUTER JOIN - príklad - predpokladajme, že tabuľka student(id:INTEGER, meno:VARCHAR(20), id_mesto INTEGER) obsahuje záznamy (1, 'Ján Hraško', 1), (2, 'Ali Baba', NULL) a tabuľka mesto(id:INTEGER, nazov:VARCHAR(20)) záznamy (1, 'Hrašovík'), (2, 'Šalgovík') - výsledkom dopytu SELECT * FROM student s JOIN mesto m ON s.id_mesto = m.id (alebo ekvivalentne SELECT * FROM student s INNER JOIN mesto m ON s.id_mesto = m.id) je tabuľka s jediným záznamom (1, 'Ján Hraško', 1, 'Hrašovík') - výsledkom dopytu SELECT * FROM student s LEFT OUTER JOIN mesto m ON s.id_mesto = m.id je tabuľka so záznamami (1, 'Ján Hraško', 1, 'Hrašovík') a (2, 'Ali Baba', NULL, NULL) - výsledkom dopytu SELECT * FROM student s RIGHT OUTER JOIN mesto m ON s.id_mesto = m.id je tabuľka so záznamami (1, 'Ján Hraško', 1, 'Hrašovík') a (NULL, NULL, 2, 'Šalgovík') - výsledkom dopytu SELECT * FROM student s FULL OUTER JOIN mesto m ON s.id_mesto = m.id je tabuľka so záznamami (1, 'Ján Hraško', 1, 'Hrašovík'), (2, 'Ali Baba', NULL, NULL) a (NULL, NULL, 2, 'Šalgovík') ---------------------------------------------------------------------- 4.4 Zložitejšie nadstavby nad príkazom SELECT ---------------------------------------------------------------------- - množinové operácie (INTERSECT, UNION, EXCEPT) - aby bolo možné množinové uperácie urobiť, musia byť obe tabuľky kompatibilné - musia mať rovnaký počet riadkov a rovnaké datové typy - význam - INTERSECT - prienik - UNION - zjednotenie - EXCEPT - rozdiel - syntax (zjednodušená): select_príkaz_1 množinová_operácia [ALL] select_príkaz_1 [ORDER BY špecifikácia_triedenia] - pri použití ALL sa neodstránia duplicity (zato je však operácia UNION ALL rýchlejšia než UNION) - v prípade, že nesedia názvy stĺpcov v oboch SELECT-och, v ORDER BY možno použiť len poradie stĺpcov - príklady - SELECT meno, priezvisko FROM student UNION ALL SELECT meno, priezvisko FROM ucitel ORDER BY priezvisko - zoznam všetkých študentov i učiteľov - SELECT meno FROM student INTERSECT SELECT priezvisko FROM student ORDER BY 1 - zoznam prievisk študentov, ktoré sa zhodujú s krstným menom niektorého študenta, ale každé iba raz - v ORDER BY klauzule môže byť iba číslo - pomocné tabuľky - klauzula WITH - ak na získanie výslednej tabuľky nestačia doterajšie prostriedky, možno pomocou klauzuly WITH vytvoriť pomocné tabuľky a tie potom použiť pri konštrukcii výsledku - syntax: WITH definícia_pomocnej_tabuľky [, definícia_pomocnej_tabuľky] select_príkaz, kde definícia_pomocnej_tabuľky := názov_pomocnej_tabuľky (názov_stĺpca_pomocnej_tabuľky [, názov_stĺpca_pomocnej_tabuľky]) AS (select_príkaz) - príklad - WITH mozne (id, kredit) AS ( SELECT s.id, SUM(kredit) FROM student s, zapisane z, predmet p WHERE s.id = z.id_student AND p.id = z.id_predmet GROUP BY s.id ), ziskane (id, kredit) AS ( SELECT s.id, SUM(kredit) FROM student s, zapisane z, predmet p WHERE s.id = z.id_student AND p.id = z.id_predmet AND znamka IS NOT NULL GROUP BY s.id ) SELECT s.id, s.meno, s.priezvisko, m.kredit, z.kredit FROM sk.student s, mozne m, ziskane z WHERE m.id = s.id AND z.id = s.id ORDER BY 3, 2; - najprv sme si vo WITH klauzule vytvorili pomocnú tabuľku mozne, kde sú id študentov so sumami kreditov, ktoré mohli získať, a pomocnú tabuľku ziskane, kde sú id študentov so sumami nimi naozaj získaných kreditov; tieto pomocné tabuľky sme potom zaangažovali do výsledného SELECT-u - slabšou alternatívou je definovanie tabuľky priamo vo FROM klauzule - syntax (časť): - SELECT ... FROM (select_príkaz) AS meno_pomocnej_tabuľky(meno_stĺpca_pomocnej_tabuľky, [meno_stĺpca_pomocnej_tabuľky]) - príklad - SELECT AVG(suma) FROM ( SELECT t.kod, SUM(t.poplatok) FROM student s JOIN izba i ON s.id_izba = i.id JOIN typ_izby t ON i.id_typ = t.id GROUP BY t.kod ) AS zaplatene(kod, suma) - v tabuľke zaplatene sa vypočíta, koľko bývajúci študenti zaplatili za ten-ktorý typ izby, vo vonkajšom príkaze sa zistí priemerná hodnota týchto čísel - tranzitívny uzáver - špeciálnou možnosťou SQL vo verzii DB2 je vyjadrenie rekurzívneho uzáveru pomocou rekurzie - príklad - predpokladajme, že máme rodokmeň reprezentovaný tabuľkou clen (id: INTEGER, id_otec: INTEGER, meno: VARCHAR(10) (s primárnym kľúčom id), v ktorej id_otec je cudzím kľúčom do tej istej tabuľky a znamená id otca - priameho predchodcu cez práve jednu generáciu; "praotec" v našej databáze bude mať v stĺpci id:otca prázdnu hodnotu - na to, aby sme získali tabuľku s dvojicami predkov a potomkov cez ľubovoľný počet generácií, vyrobíme pomocnú tabuľku potomkovia, ktorá bude zložená z dvoch častí spojených UNION-om; v prvej časti (prvý krok rekurzie)vlastne len skopírujeme tabuľku clen (až na riadok praotca), ktorá bude znamenať rozdiel jednej generácie, v druhej časti, kde je skrytá samotná rekurzia, na tabuľku potomkovia opakovane naväzujeme tabuľku clen - každý ďalší medzivýsledok bude mať o jednu generáciu viac (napodobňujeme tak proces spomínaný v časti 3.2) - WITH potomkovia (id, id_potomok) AS ( SELECT koren.id_otec, koren.id FROM clen koren WHERE koren.id_otec IS NOT NULL UNION ALL SELECT otec.id, dieta.id FROM potomkovia otec, clen dieta WHERE otec.id_potomok = dieta.id_otec ) SELECT predok.id, predok.meno, potomok.id, potomok.meno FROM potomkovia p, clen predok, clen potomok WHERE predok.id = p.id AND potomok.id = p.id_potomok ORDER BY 1, 2 ---------------------------------------------------------------------- 4.4 Aktualizácia dát ---------------------------------------------------------------------- - aktualizačné príkazy v SQL - INSERT - vkladanie nových záznamov - syntax: INSERT INTO meno_tabuľky [(meno_stĺpca [, meno_stĺpca])] VALUES hodnota_záznamu [, hodnota_záznamu], kde hodnota_záznamu := (hodnota_stĺpca [, hodnota_stĺpca]) alebo INSERT INTO meno_tabuľky [(meno_stĺpca [, meno_stĺpca])] select_príkaz - počet, poradie a dátové typy stĺpcov musia korešpondovať s príslušnými hodnotami stĺpcov resp. so stĺpcami príkazu SELECT - v prípade, že mená stĺpcov nie sú uvedené, predpokladá sa, že sú všetky a v takom poradí, v akom boli definované pri vytváraní tabuľky - stĺpce, ktoré nie sú uvedené, sú vyplnené automaticky, a to podľa definície tabuľky (spravidla prázdnou hodnotou, tu sa však vyžaduje, aby príslušný stĺpec prázdne hodnoty pripúšťal (t.j aby nebol NOT NULL)) - príklady - majme ďalsiu tabuľku - osoba(_id_: INTEGER, meno: VARCHAR(30)) - príkaz INSERT INTO osoba VALUES (1, 'Ján Hraško') vloží do tabuľky osoba záznam (1, 'Ján Hraško') (ak tam ešte záznam s takou hodnotou primárneho kľúča nie je) - príkaz INSERT INTO osoba VALUES (1, 'Ján Hraško'), (2, 'Ján Polienko') vloží do tabuľky osoba záznamy (1, 'Ján Hraško') a (2, 'Ján Polienko') (ak tam ešte záznamy s takými hodnotami primárneho kľúča nie sú) - príkaz INSERT INTO osoba (id) VALUES (1) vloží do tabuľky osoba záznam (1, NULL') (ak tam ešte záznam s takou hodnotou primárneho kľúča nie je) - príkaz INSERT INTO osoba SELECT id, meno || ' ' || priezvisko FROM student vloží do tabuľky osoba záznamy odvodené zo záznamov z tabuľky student (ak tam ešte záznamy s takými hodnotami primárneho kľúča nie sú) - DELETE - mazanie existujúcich záznamov - syntax: DELETE FROM meno_tabuľky [WHERE podmienka] - vymažú sa všetky záznamy, ktoré spĺňajú uvedenú podmienku (ktorá môže byť aj zložená) - ak klauzula WHERE nie je uvedená, chápe sa ako pravdivá , t.j. vymažú sa všetky záznamy - celý obsah tabuľky - príklady - DELETE FROM osoba WHERE id=1 - vymaže sa jeden záznam - DELETE FROM osoba WHERE meno LIKE 'Ján %' - vymažú sa všetky záznamy, ktorých hodnota atribútu meno začína na 'Ján' - DELETE FROM osoba WHERE id IN (SELECT id FROM student) - vymažú sa všetci študenti - UPDATE - zmena hodnôt existujúcich záznamov - syntax: UPDATE meno_tabuľky SET nastavenie_hodnoty_stĺpca [, nastavenie_hodnoty_stĺpca] [WHERE podmienka], kde nastavenie_hodnoty_stĺpca := meno_stĺpca = hodnota - prepíšu sa všetky záznamy, ktoré spĺňajú uvedenú podmienku (ktorá môže byť aj zložená) - ak klauzula WHERE nie je uvedená, chápe sa ako pravdivá , t.j. vymažú sa všetky záznamy - celý obsah tabuľky - hodnota nemusí byť len konštanta, môžu v nej figurovať aj oné stĺpce tabuľky, ba aj ten istý - príklady - UPDATE student SET meno='Jozef' WHERE id=1 - upraví sa meno študenta s id 1 - UPDATE student SET meno='Jozef', priezvisko='Mrkvička' WHERE id=1 - upraví sa meno a priezvisko študenta s id 1 - UPDATE student SET meno='Jozef' WHERE meno='Jožo' - upraví sa meno všetkých Jožov na Jozef - UPDATE osoba SET meno='študent '|| meno WHERE id IN (SELECT id FROM student) - upravia sa mená všetkých osôb, ktoré sú študentmi, tak, že sa pred nich predpíše slovo 'študent' - pri vhodnej definícii možno upravovať aj hodnoty v "pohľade", upraví sa tým pôvodná tabuľka ---------------------------------------------------------------------- 4.5 Triggery ---------------------------------------------------------------------- - triggery - pri zmene nejakých hodnôt v niektorej tabuľke môže byť vhodné či nutné meniť aj stav ďalších hodnôt v inej alebo aj v tej istej tabuľke; je preto vhodné vytvoriť trigger - prostriedok, ktorý túto súslednosť zabezpečí - syntax (časť): CREATE TRIGGER meno_triggeru {AFTER | ON CASCADE BEFORE} {INSERT | DELETE | UPDATE[(zoznam_stĺpcov)} ON meno_tabuľky [REFERENCING [OLD AS zvolené_meno_starého_záznamu] [NEW AS zvolené_meno_nového_záznamu] ] FOR EACH {ROW | STATEMENT} MODE DB2SQL [WHEN (podmienka)] akcia - trigger sa môže spustiť pred (ON CASCADE BEFORE) alebo po (AFTER) zmene a vyvolá ho iba príslušná operácia - ak zoznam stĺpcov pri UPDATE prázdny, trigger sa týka zmien všetkých stĺpcov tabuľky - pri nastavovaní hodnôt možno použiť aj nové alebo staré (prepisované) hodnoty, čo sa uvedie v sekcii REFERENCING OLD resp. NEW - pod akciou sa najčastejšie rozumie nastavenie nejakej hodnoty - akcia sa vykoná iba po splnení podmienky; ak podmienka nie je uvedená, akcia sa vykoná vždy - príklady - CREATE TRIGGER student_plus resp. student_minus AFTER INSERT resp. DELETE ON student FOR EACH ROW MODE DB2SQL UPDATE statistika SET hodnota = hodnota + resp. - 1 WHERE parameter='pocet studentov' - po pridaní nového/zmazaní ľubovoľného existujúceho záznamu sa v tabuľke statistika(parameter, hodnota) automaticky o 1 zväčší/zmenší hodnota x v zázname ('pocet studentov', x) - CREATE TRIGGER student_zmena AFTER UPDATE ON student REFERENCING OLD AS o FOR EACH ROW MODE DB2SQL INSERT INTO student_historia (id, meno, priezvisko, datum_do) VALUES (o.id, o.meno, o.priezvisko, CURRENT TIME) - po zmene údajov o študentovi sa do tabuľky histórie zmien vloží nový záznam so starými hodnotami študenta a aktuálnou pečiatkou - CREATE TRIGGER t0 NO CASCADE BEFORE INSERT ON zapas REFERENCING NEW AS NOVY FOR EACH ROW MODE DB2SQL WHEN (NOVY.goly1