You are on page 1of 887

Databázy (1)

Prednášky

Alexander Šimko
simko@fmph.uniba.sk
Contents I

Organizačné veci

Čo je databázový systém a prečo by ma mal zaujímať?

Relačný model dát a SQL

Základné SQL príkazy

Dátové typy

Výrazy

WHERE a NULL
Contents II

Default hodnoty stĺpcov

Sekvencie a automaticky inkrementované čísla

SELECT podrobnejšie

JOIN - Získavanie dát z viacerých tabuliek spájaním

JOIN a UPDATE, DELETE a INSERT

Množinové operácie

Integritné obmedzenia
Contents III

UPSERT

Podmienené výrazy

Agregovanie dát

Viac zoskupovaní naraz

Normalizácia neformálne

Návrh databáz / Dátové modelovanie

Návrh databáz / Dátové modelovanie – Pokračovanie


Contents IV

Vnorené SELECTy

Konštrukcia WITH

Základné info o texte

Textové typy

Práca s textom

Fulltextové vyhľadávanie

Práca s dátumom a časom


Contents V
Náhodné čísla

Generovanie dát

Aktualizovanie štruktúry databázy

Skúška

Čo bude na DB2?
Organizačné veci

Section 1

Organizačné veci
Organizačné veci

O prednášajúcom

I Alexander Šimko
I miestnosť I-6
I simko@fmph.uniba.sk
I http://dai.fmph.uniba.sk/~simko
Organizačné veci

O predmete

I http://dai.fmph.uniba.sk/~simko/teaching/db1
I zameraný na tvorbu softvéru s použitím relačných databáz
I PostgreSQL
Organizačné veci

O predmete

I relačný model dát


I práca s relačnou databázou v jazyku SQL
I návrh vlastnej databázy
I generovanie testovacích/prezentačných dát
I evolúcia produkčnej databázy
Organizačné veci

Na predmet nadväzuje 1-AIN-222/15 Databázy (2)

I pristupovanie k databáze z imperatívneho jazyka


I vzory na organizáciu kódu
I databázové a aplikačné transakcie
I optimalizácia SQL príkazov
I objektovo-orientovaný prístup k relačnej databáze
I pohľad dovnútra databázového systému
Organizačné veci

Priebeh predmetu

2h prednášok týždenne
I Streda 09:50 B

2h cvičení týždenne
I streda 16:30 H-6, štvrtok 14:50 H-6, štvrtok 16:30 H-6
I za počítačom
I budeme programovať a riešiť úlohy
Organizačné veci

Hodnotenie – Čo bude

1. priebežná písomka (25b)


I 06.11.2018 o 18:10 v miestnostiach A a B

2. priebežná písomka (25b)


I 11.12.2018 o 18:10 v miestnostiach A a B

I na papier
I všetko, čo dovtedy preberieme
I úlohy budú praktické: napíšte SQL príkaz, vyhodnoťte SQL príkaz,
napíšte, kde je chyba a pod
I dokopy z dvoch písomiek treba získať aspoň 25b
I minimum z jednej písomky nie je
I opravné písomky nebudú
Organizačné veci

Hodnotenie – Čo bude

Záverečná písomná skúška (50b)


I termíny vypíšem po druhom týždni, kedy sa ukončí zápis
I na papier
I všetko
I úlohy budú praktické: napíšte SQL príkaz, vyhodnoťte SQL príkaz,
napíšte, kde je chyba a pod
I zo skúšky treba získať aspoň 25b
Organizačné veci

Hodnotenie – Čo nebude

I žiadne priebežné rozcvičky na cvikách


I žiadne bodované domáce úlohy
I žiadne bodované úlohy na cvičeniach
I žiaden projekt
Organizačné veci

Stupnica

h90 − 100i A výborne – vynikajúce výsledky len s minimálnymi


chybami
h80 − 90) B veľmi dobre – nadpriemerné výsledky s menšími
chybami
h70 − 80) C dobre – vcelku dobré, priemerné výsledky
h60 − 70) D uspokojivo – dobré výsledky, ale vyskytujú sa
významné chyby
h50 − 60) E dostatočne – výsledky vyhovujú minimálnym
kritériam
h0 − 50) FX nedostatočne – absolvovanie predmetu si
vyžaduje vynaložiť ešte značné úsilie a množstvo
práce zo strany študenta
Organizačné veci

2-EFM-140/15 Databázy – SQL

I máte za to 3 kredity
I budete hodnotení na základe 2 pribežných písomiek
I skúška nebude
I učivo po cca 8. prednášku (presne si ešte povieme)
Organizačné veci

Výsledky z minulosti – 1-AIN-221/15 Databázy (1)

42.86 2015/16
40 38.1 37.1 2016/17
35.82
2017/18
30
% študentov

19.64 19.64
20
14.93
13.43 13.43 11.94 10.45
10 8.27.14 7.14
6.2 6.2
3.57 4.1

0
FX E D C B A
Organizačné veci

Výsledky z minulosti – 2-EFM-140/15 Databázy – SQL

80
2017/18
60
60
% študentov

40

20
20
13.33
6.67
0 0
0

FX E D C B A
Organizačné veci

Koľko by som sa mal venovať predmetu?

I predmet je za 5 kreditov
I kreditový systém predpokladá záťaz 25-30 hodín na kredit
I to dáva 5 ∗ 25 = 125 hodín práce
I máme 14 týždňov = 13 za semester + 1 cez skúškové
I 125 hodín / 14 týždňov = 8,9 hodín práce týždenne
I prednášky a cviká zaberajú 1,5 + 1,5 = 3 hodiny týždenne
I ostáva v priemere 5,9 hodín samoštúdia týždenne
Čo je databázový systém a prečo by ma mal zaujímať?

Section 2

Čo je databázový systém a prečo by ma mal zaujímať?


Čo je databázový systém a prečo by ma mal zaujímať? Výzvy pri tvorbe softvéru

Výzvy pri tvorbe softvéru

I perzistencia,
I veľké množstvo dát,
I veľké množstvo používateľov pracujúcich naraz,
I výpadky, napr. počítačovej siete, elektriny a iné chyby.
Čo je databázový systém a prečo by ma mal zaujímať? Výzvy pri tvorbe softvéru

Perzistencia

I chceme aby po vypnutí a zapnutí systému dáta nezmizli,


I odkladanie na disk, pásky, ...
Čo je databázový systém a prečo by ma mal zaujímať? Výzvy pri tvorbe softvéru

Veľké množstvo dáť

I do operačnej pamäte sa jednoducho nezmestí,


I musíme ich ukladať na disky, pásky, atď,
I do operačnej pamäte musíme vždy načítať len relevantné dáta,
I čítanie/zápis nad diskami a páskami je výrazne pomalší ako nad
operačnou pamäťou,
I potrebujeme algoritmy, ktoré dokážu efektívne spracovávať veľké
množstvo údajov na pomalých diskoch
Čo je databázový systém a prečo by ma mal zaujímať? Výzvy pri tvorbe softvéru

Veľké množstvo používateľov pracujúcich naraz

Porebujeme algoritmy, ktoré sa dokážu vysporiadať s problémami, ktoré


vznijakú pri súbežnom prístupe k dátam:
I stratená zmena (lost update),
I nekonzistentné čítanie (inconsistent read),
I ...
Čo je databázový systém a prečo by ma mal zaujímať? Výzvy pri tvorbe softvéru

Stratená zmena (lost update)

Majiteľ vyberie z účtu N = e 300:


(A1) do X načítaj stav účtu, nech je to e 500
(A2) Skontroluj, či X ≥ N
(A3) zmeň stav účtu na X − N = e 200
Čo je databázový systém a prečo by ma mal zaujímať? Výzvy pri tvorbe softvéru

Stratená zmena (lost update)

Majiteľ vyberie z účtu N = e 300:


(A1) do X načítaj stav účtu, nech je to e 500
(A2) Skontroluj, či X ≥ N
(A3) zmeň stav účtu na X − N = e 200

Disponent účtu v momente keď sa vykoná (A2) vyberie M = e 400


Čo je databázový systém a prečo by ma mal zaujímať? Výzvy pri tvorbe softvéru

Stratená zmena (lost update)

Disponent účtu v momente keď sa vykoná (A2) vyberie M = e 400


(A1) do X načítaj stav účtu, nech je to e 500
(A2) Skontroluj, či X ≥ N
(B1) do Y načítaj stav účtu, je to stále to e 500
(B2) Skontroluj, či Y ≥ M
(B3) zmeň stav účtu na Y − M = e 100
(A3) zmeň stav účtu na X − N = e 200
Čo je databázový systém a prečo by ma mal zaujímať? Výzvy pri tvorbe softvéru

Stratená zmena (lost update)

Disponent účtu v momente keď sa vykoná (A2) vyberie M = e 400


(A1) do X načítaj stav účtu, nech je to e 500
(A2) Skontroluj, či X ≥ N
(B1) do Y načítaj stav účtu, je to stále to e 500
(B2) Skontroluj, či Y ≥ M
(B3) zmeň stav účtu na Y − M = e 100
(A3) zmeň stav účtu na X − N = e 200

Zmena stavu účtu na e 100 sa stratila.

Ako dôsledok sa z účtu vybralo e 300 + e 400 = e 700, čo je viac než


pôvodný stav e 500.
Čo je databázový systém a prečo by ma mal zaujímať? Výzvy pri tvorbe softvéru

Zotavenie sa z výpadkov

Prevod N peňazí medzi účtom A a B:


(1) Odčítaj N z účtu A.
(2) Pripočítaj N k účtu B.

Čo ak sa po úspešnom kroku (1) a zapísaní údajov na disk a pred


vykonaním kroku (2) systém vypne kvôli výpadku elektriny?
Čo je databázový systém a prečo by ma mal zaujímať? Databázové systémy

Čo je to databázový systém?

Ak teda spomínané problémy začneme nejako seriózne riešiť, vytvoríme


databázový systém, ktorý sa skladá z
I databázy - kolekcie dát, typicky uloženej vo veľkých súboroch na
disku,
I systému riadenia bázy dát - programového kódu, ktorý
premyslenými algoritmami spravuje dátabázu a rieši spomínané
problémy.
Čo je databázový systém a prečo by ma mal zaujímať? Databázové systémy

Vyhotovenie databázových systémov

Je jedno, či je systém riadenia bázy dát:


I knižnica, ktorú si k svojmu projektu pripojíme, alebo
I samostne bežaci systém, na ktorý sa pripájame napr. po sieti
Čo je databázový systém a prečo by ma mal zaujímať? Databázové systémy

Druhy databázových systémov

V závislosti od toho, akým spôsobom sú dáta organizované v databáze,


existuje viacero druhov databázových systémov:
I sieťové
I hierachické
I relačné
I XML databázy
I dekuktívne databázy
I dokumentové
I objektovo orientované
I ...
Čo je databázový systém a prečo by ma mal zaujímať? Databázové systémy

Tento predmet

Na tomto predmete sa budeme zaoberať relačnými databázami, lebo:


I sú v súčasnosti asi najviac rozšíreným typom databáz,
I sú postavené na solídnom teoretickom základe a existuje množstvo
produkčných implementácii,
I väčšina z vás sa s nimi v praxi stretne.
Čo je databázový systém a prečo by ma mal zaujímať? Databázové systémy

Databázové predmety na AIN

1-AIN-121 Matematika 1
Úvod do matematického myslenia
1-AIN-221
Databázy (1)
1-AIN-160 Matematika 3
Diskrétna matematika
1-AIN-222
Databázy (2)
1-AIN-412 Matematika 4
Logika pre informatikov
1-AIN-305
Deduktívne databázy
1-AIN-315
Semištruktúrované dáta
(XML, JSON a NoSQL)
Relačný model dát a SQL

Section 3

Relačný model dát a SQL


Relačný model dát a SQL Relačný model dát

Relačný model dát

Codd, E. F. (1970).
A relational model of data for large shared data banks

Oddelenie reprezentácie dát a spôsobu manipulácie s nimi:


I dáta sú reprezentované pomocou tabuliek, ktoré nezohľadňujú ako sa
bude s údajmi v systéme pracovať,
I s dátami pracujeme pomocou špeciálneho jazyka (SQL), ktorému
databázový systém rozumie.
Relačný model dát a SQL Relačný model dát

Definícia tabuľky

Tabuľka je dvojrozmená dátová štuktúra riadkov a stĺpcov:


I tabuľka má jedinečné meno,
I stĺpec má meno a pevne daný typ,
I stĺpec má v rámti tabuľky jedinečné meno,
I hodnoty v danom stĺpci môžu byť iba daného typu,
I na poradí riadkov záleží,
I môžeme mať duplicitné riadky.
Relačný model dát a SQL Relačný model dát

Príklad tabuliek

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10

users
id name email country_id
1 fan123 fan123@gmail.com 1
2 johnny spam@spam.com 4

countries ratings
id name user_id film_id rating
1 Slovakia 1 2 10
4 Czech Republic 2 1 9
Relačný model dát a SQL Relačný model dát

Odkazovanie sa medzi tabuľkami

users
id name email country_id
1 fan123 fan123@gmail.com 1
2 johnny spam@spam.com 4

countries
id name
1 Slovakia
4 Czech Republic

johnny je z krajiny Czech Republic

Čísla, pomocou ktorých sa odkazujeme medzi tabuľkami sme vložil my.


Špeciálny význam majú iba pre nás. Pre databázový systém sú to len čísla
ako hociktoré iné.
Relačný model dát a SQL Relačný model dát

Odkazovanie sa medzi tabuľkami

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10

users
id name email country_id
1 fan123 fan123@gmail.com 1
2 johnny spam@spam.com 4

ratings
user_id film_id rating
1 2 10
2 1 9

johnny ohodnotil film Léon hodnotením 9


Relačný model dát a SQL Relačný model dát

Kľúč tabuľky

Kľúč tabuľky je množina stĺpcov, podľa ktorých vieme riadky tabuľky


jednoznačne identifikovať.
I jednoduchý – ak sa skladá iba z jedného stĺpca,
I zložený – ak sa skladá z viacerých stlpcov
Relačný model dát a SQL Relačný model dát

Kľúč tabuľky – príklad

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10

I {id} je jednoduchý kľúč,


I {name} je jednoduchý kľúč,
I {year } je jednoduchý kľúč,
I {id, name} je zložený kľúč,
I ...,
I {price} ale nie je kľúč
Relačný model dát a SQL Relačný model dát

Koľko môže byť kľúčov?

Všetky možnosti sú prípustné:


I viac než jeden – to sme už videli
I práve jeden,
I žiaden.
Relačný model dát a SQL Relačný model dát

Práve jeden kľúč

ratings
user_id film_id rating
1 1 9
1 2 10
2 1 9
2 2 9
2 2 10

I jediným kľúčom je {user _id, film_id, rating }


Relačný model dát a SQL Relačný model dát

Žiaden kľúč

ratings
user_id film_id rating
1 1 9
1 1 9
Relačný model dát a SQL Relačný model dát

Umelý kľúč

Ak tabuľka nemá žiaden kľúč a potrebujeme rozlíšiť riadky, musíme si


vytvoriť umelý kľúč.

ratings
id user_id film_id rating
1 1 1 9
2 1 1 9
Relačný model dát a SQL Relačný model dát

Umelý kľúč

I Kľúče tabuľky si budeme musiet v aplikácii predávať hore-dole medzi


funkciami/metódami.
I Preto je v prípade zloženého kľúča vhodné zaviesť si nejaký umelý
jednoduchý kľúč.
Relačný model dát a SQL Relačný model dát

Primárny klúč

I tabuľka môže mať viac kľúčov,


I má zmysel vybrať si jeden kľúč a tento používať všade v aplikácii na
identifikovanie riadkov,
I takýto kľúč budeme volať primárny kľúč
Relačný model dát a SQL Relačný model dát

Cudzí kľúč

Cudzí kľúč je množina stĺpcov tabuľky, ktorou sa daná tabuľka odkazuje na


primárny kľúč inej tabuľky
Relačný model dát a SQL Relačný model dát

Cudzí kľúč – príklad

users
id name email country_id
1 fan123 fan123@gmail.com 1
2 johnny spam@spam.com 4

countries
id name
1 Slovakia
4 Czech Republic

I {id} je primárnym kľúčom tabuľky countries


I {countr _id} je cudzím kľúčom tabuľky users, ktorým sa odkazujeme
na primárny kľúč {id} tabuľky countries
Relačný model dát a SQL Relačný model dát

Štruktúra tabuľky vs dáta tabuľky

Štruktúra tabuľky (schéma)


I názov tabuľky: films
I názvy stĺpcov a ich typy:
1. id : celé číslo
2. name : textový reťazec
3. year : celé číslo
4. price : desatinné číslo
I primárny kľúč : {id}
I cudzie kľúče : žiadne
Relačný model dát a SQL Relačný model dát

Štruktúra tabuľky vs dáta tabuľky

Dáta tabuľky (riadky)


1 Léon: The Professional 1994 10
2 Django Unchained 2012 10
Relačný model dát a SQL Relačný model dát

Odkiaľ sa zobral názov "relačný"?

Názov relačného modelu pochádza z toho, že článok, v ktorom bol


zavedený je písaný matematickým jazykom. Dáta sú organizované v
reláciach v matematickom ponímaní:

relácia je množina usporiadaných n-tíc.

Naše tabuľky zodpovedajú reláciam a riadky n-ticiam.

films = {
(1, Léon : The Professional, 1994, 10),
(2, Django Unchained, 2012, 10),
}
Relačný model dát a SQL Relačný model dát

Rozdiel medzi reláciami a tabuľkami

I duplicity,
I poradie.
Relačný model dát a SQL SQL

Structured Query Language (SQL)

I jazyk na prácu s databázovým systémom


I príkazy, ktoré posielame databázovému systému a ten nejako reaguje a
posiela nám naspäť odpoveď
I nie je case-sensitive
I je štandardizovaný, ale
I implementácie sa odchyľujú od štandardu
Relačný model dát a SQL SQL

Príklad SQL

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10

SELECT name, price


FROM films
WHERE id = 2

name price
Django Unchained 10
Relačný model dát a SQL SQL

Delenie SQL

Data Definition Language (DDL)


I príkazy na definíciu dát - vytváranie, aktualizovanie, mazanie tabuliek,
...
Data Query Language (DQL)
I príkazy na získavanie dát
Data Manipulation Language (DML)
I príkazy na manipuláciu s dátami – vkladanie, aktualizovanie, mazanie
riadkov
Data Control Language (DCL)
I príkazy na riadenie prístupu k dátam - pridávanie, odoberanie
používateľov, prístupových práv, ...
Základné SQL príkazy

Section 4

Základné SQL príkazy


Základné SQL príkazy Dva základné DDL príkazy

CREATE TABLE – Syntax

CREATE TABLE názov_tabuľky


(
názov_stĺpca_1 typ_stĺpca_1,
názov_stĺpca_2 typ_stĺpca_2,
...
názov_stĺpca_n typ_stĺpca_n
)
Základné SQL príkazy Dva základné DDL príkazy

CREATE TABLE – Príklad

CREATE TABLE films


(
id integer,
name varchar(50),
year integer,
price numeric
)

films
id name year price
Základné SQL príkazy Dva základné DDL príkazy

DROP TABLE – Syntax

DROP TABLE názov_tabuľky


Základné SQL príkazy Dva základné DDL príkazy

DROP TABLE – Príklad

DROP TABLE films


Základné SQL príkazy Štyri základné DML príkazy

INSERT INTO – Syntax

INSERT INTO názov_tabuľky


(názov_stĺpca_1, ..., názov_stĺpca_n)
VALUES
(hodnota_r1_s1, ..., hodnota_r1_sn),
...
(hodnota_rm_s1, ..., hodnota_rm_sn)

I vloži vymenované riadky do tabuľky


Základné SQL príkazy Štyri základné DML príkazy

INSERT INTO – Syntax

INSERT INTO films


(id, name, year, price)
VALUES
(1, ’Léon: The Professional’, 1994, 10),
(2, ’Django Unchained’, 2012, 10)

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10
Základné SQL príkazy Štyri základné DML príkazy

SELECT – Syntax

SELECT názov_stĺpca_1, ..., názov_stĺpca_n


FROM názov_tabuľky
[WHERE podmienka]

I z tabuľky vyberie riadky, pre ktoré sa podmienka vyhodnotí na TRUE


Základné SQL príkazy Štyri základné DML príkazy

SELECT – Príklad

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10

SELECT name, price


FROM films
WHERE id = 2

name price
Django Unchained 10
Základné SQL príkazy Štyri základné DML príkazy

UPDATE – Syntax

UPDATE názov_tabuľky
SET názov_stĺpca_1 = nová_hodnota_1,
...,
názov_stĺpca_n = nová_hodnota_n
[WHERE podmienka]

I aktualizuje riadky tabuľky, pre ktoré sa podmienka vyhodnotí na TRUE


Základné SQL príkazy Štyri základné DML príkazy

UPDATE – Príklad

films
id name year price
1 Léon: The Professional 1993 10
2 Django Unchained 2012 10

UPDATE films
SET year = 1994
WHERE id = 1

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10
Základné SQL príkazy Štyri základné DML príkazy

DELETE – Syntax

DELETE FROM názov_tabuľky


[WHERE podmienka]

I z tabuľky odstráni riadky, pre ktoré sa podmienka vyhodnotí na TRUE


Základné SQL príkazy Štyri základné DML príkazy

DELETE – Príklad

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10

DELETE FROM films


WHERE id = 2

films
id name year price
1 Léon: The Professional 1994 10
Základné SQL príkazy Štyri základné DML príkazy

CRUD operácie nad tabuľkou

Create a new row INSERT


Read a row with given id SELECT
Update a row with given id UPDATE
Delete a row with given id DELETE
Dátové typy

Section 5

Dátové typy
Dátové typy Číselné typy

Celé čísla

smallint
I 2 bajty
I od -32768 do +32767

integer
I 4 bajty
I od -2147483648 do +2147483647

bigint
I 8 bajtov
I od -9223372036854775808 do +9223372036854775807
Dátové typy Číselné typy

Nepresné desatinné čísla

real
I 4 bajty
I typicky od ±1 × 10−37 do ±1 × 10+37 (platformovo závislé)
I 6 desatinných miest

double precision
I 8 bajtov
I typicky od ±1 × 10−307 do ±1 × 10+308 (platformovo závislé)
I 15 desatinných miest
Dátové typy Číselné typy

Nepresné desatinné čísla

Nepresnosť znamená, že nevedia uložiť presne každé číslo z podporovaného


rozsahu
Dátové typy Číselné typy

Nepresné desatinné čísla – 32b IEEE-754 formát

znamienko exponent mantisa


z1 e1 . . . e8 m1 m2 . . . m23

hodnota = znamienko × 2exponent × mantisa


znamienko = (−1)z1
exponent = (e1 . . . e8 )10 − 127
23
X mi
mantisa = 1 +
2i
i=1

číslo 5:
znamienko exponent mantisa
0 10000001 01000000000000000000000
1
(−1)0 × 2129−127 × (1 + ) = 1 × 22 × 1.25 = 5
4
Dátové typy Číselné typy

číslo 3.3:
znamienko exponent mantisa
0 10000000 10100110011001100110011

1 1 1
(−1)0 × 2128−127 × (1 + + + + ...) =
2 8 64
= 1 × 2 × 1.649999976158142 = 3.299999952316284

http://www.h-schmidt.net/FloatConverter/IEEE754.html
Dátové typy Číselné typy

Nepresné desatinné čísla

Počítanie s takým dátovym typom dáva nepresné výsledky:

3.31 − 3.3 = 0.00999999

A teda testovanie rovnosti nemá zmysel:

3.31 − 3.3 6= 0.01

Treba testovať, či je rozdiel hodnôt ešte v povolenej tolerancii :

abs((3.31 − 3.3) − 0.01) ≤ 

Hodnotu , napr. 0.001, volíme podľa konkétnej úlohy.


Dátové typy Číselné typy

Presné desatinné čísla

numeric
I premenlivá dĺžka
I 131072 miest pred desatinnou čiarkou
I 16383 miest za desatinnou čiarkou

3.31 − 3.3 = 0.01


Dátové typy Číselné typy

Použiť presné či nepresné desatinné čísla?

Technické výpočty, simulácie, kde záleži na výkone


I nepresné desatinné čísla sú väčšinou vhodné

Práca s peňažnými údajmi


I musíme použiť presné desatinné čísla
I ináč nám budú vznikať peňažné rozdiely

Táto otázka nie je špecifická pre SQL:


I Python – float vs decimal
I Java – double vs BigDecimal
Dátové typy Číselné typy

Číselné literály – syntax

Literál je hodnota napísaná priamo v zdrojovom kóde. Príklady zápisov:


I 42
I 3.5
I 4.
I .001
I 5e2 = 5 × 102
I 1.925e-3 = 1.925 × 10−3
Dátové typy Číselné typy

Číselné literály – ako sa určuje dátový typ


numeric
áno
desatinná
čiarka
integer
alebo
exponent nie áno
zmestí
sa do bigint
integer nie áno

zmestí sa
do bigint
nie

numeric
Dátové typy Číselné typy

Číselné literály pre REAL a DOUBLE PRECISION nie sú

CREATE TABLE test (


x real
)

INSERT INTO test (x) VALUES(3.3)


SELECT x FROM test
x
3.3
SELECT x FROM test WHERE x = 3.3
x
SELECT x FROM test WHERE x = 3.3::REAL
x
3.3
Dátové typy Reťazcové typy

Reťazce

varchar(n)
I reťazec dĺžky maximálne n znakov,
I kratšie reťazce zeberajú menej miesta
I ak n neuvedieme, dĺžka reťazca nie je obmedzená (PostgreSQL
špecialita)
Dátové typy Reťazcové typy

Textové literály

sú postupnosti znakov uzavreté v apostrofoch

’Janko Hraško’

Ak chceme v reťazci použiť apostrof, musíme ho zdvojiť

’Diannne’’s horse’

Pozor: dva apostrofy za sebou a nie úvodzovky


Dátové typy Reťazcové typy

Textové literály

Textový literál môže byť rozdelený na viacerých riadkoch.

Reťazec
’pred’

’met’

je to isté ako reťazec

’predmet’
Dátové typy Reťazcové typy

Textové literály

Reťazec musí byť ale rozdelený novým riadkom.

Toto nie je valídne

’pred’ ’met’
Dátové typy Reťazcové typy

Cčkovsky eskejpované literály

sú postupnosti znakov uzavreté v apostrofoch uvedené znakom “E”

E’Prvý riadok\nDruhý riadok’

Špeciálne znaky môžeme teraz zapísať ako:


\b backspace
\f nová strana (form feed)
\n nový riadok (newline)
\r návrat na začiatok riadku (carriage return)
\t tabulátor (tab)
\’ apostrof
\\ spätné lomítko \
\uxxxx 16 bitová hodnota Unicode znaku (x = 0 - 9, A - F)
\Uxxxxxxxx 32 bitová hodnota Unicode znaku (x = 0 - 9, A - F)
Dátové typy Reťazcové typy

Pozor na úvodzovky – častá chyba

INSERT INTO users (id, name)


VALUES (1, "johnny")

Chyba: "johnny" nie je reťazec ale identifikátor. Musíme použiť apostrofy.


INSERT INTO users (id, name)
VALUES (1, ’johnny’)
Dátové typy Reťazcové typy

Na čo sú úvodzovky?

Identifikátor (názov tabuľky, stĺpca, ...):


I musí začínať písmenom alebo podčiarkovníkom,
I ďalšie znaky môžu byť písmená, číslice, podčiarkovník

Ak chceme mať ako identifikátor inú postupnosť znakov


I musíme ju uzavrieť do úvodzoviek
Dátové typy Reťazcové typy

Úvodzovky – Príklad

CREATE TABLE "speci tabulka"


(
"speci stlpec" INTEGER
)
Dátové typy Reťazcové typy

Úvodzovky – Príklad 2
Môže sa hodiť, ak chceme tabuľku/stĺpec pomenovať nejakým vyhradeným
slovom, ktoré nám parser nevezme.
CREATE TABLE user
(
...
)

ERROR: syntax error at or near "user"

CREATE TABLE "user"


(
...
)

zbehne bez problémov.


Dátové typy Dátumové a časové typy

Dátum bez času

date
I 4 bajty
I od 4717 p.n.l. po 5874897 n.l.

Dátumový literál

DATE ’YYYY-MM-DD’

17. jún 2015:

DATE ’2015-06-17’
Dátové typy Dátumové a časové typy

Čas bez dátumu

time
I 8 bajtov
I od 0:00:00 do 24:00:00 vrátane
Dátové typy Dátumové a časové typy

Časový literál

Formát

TIME ’HH:MM:SS.SSSSSS’

Prvá milisekunda po odchode poslednej 39ky z Mlynskej

TIME ’23:05:00.000001’
Dátové typy Dátumové a časové typy

Dátum s časom

timestamp
I 8 bajtov
I rozsahy rovnako ako pri dátume a čase

Literál dátumu s časom:

TIMESTAMP ’YYYY-MM-DD HH:MM:SS.SSSSSS’


Dátové typy Typ boolean

Dátový typ – Boolean

boolean
I 1 bajt
I dve hodnoty – pravda a nepravda

Pravdivý literál

TRUE

Nepravdivý literál

FALSE
Dátové typy NULL hodnoty

NULL hodnoty

Každý dátový typ môže nadobúdať špeciálnu hodnotu NULL.

users
name telepnone_number
fan123 88083582
johnny NULL

neznáma hodnota (primárna interpretácia)


I johnny síce telefónne číslo má, ale chráni si svoje súkromie a rozhodol
sa ho nezadať.
neexistujúca hodnota (alternatívna interpretácia)
I johnny telefónne číslo nemá, lebo bojkotuje telefóny.
Dátové typy NULL hodnoty

Literál NULL

INSERT INTO users (name, telephone_number)


VALUES (’johnny’, NULL)
Výrazy

Section 6

Výrazy
Výrazy Motivácia

Motivácia: Čo ak chceme nie pôvodný ale vypočítaný


stĺpec?

Zvažujeme zdraženie nových a dlhých filmov o 10% ale minimálne o 5


jednotiek. Chceme zistiť, ako by vyzerali ceny po zdražení.
Výrazy Výzary v SQL príkazoch

SELECT – Výrazy

SELECT výraz_1, ..., výraz_n


FROM názov_tabuľky
WHERE booleovský_výraz
Výrazy Výzary v SQL príkazoch

Motivácia – Riešenie

SELECT name, greatest(price * 1.1, price + 5)


FROM films
WHERE year >= 2015 OR length > 120
Výrazy Výzary v SQL príkazoch

INSERT – Výrazy

INSERT INTO názov_tabuľky


(názov_stĺpca_1, ..., názov_stĺpca_n)
VALUES
(výraz_r1_s1, ..., výraz_r1_sn),
...
(výraz_rm_s1, ..., výraz_rm_sn)

Príklad:

INSERT INTO films


(id, name, year, price)
VALUES
(5, ’The Big Blue’, 1988, 6.8 * 0.7)
Výrazy Výzary v SQL príkazoch

UPDATE – Výrazy

UPDATE názov_tabuľky
SET názov_stĺpca_1 = výraz_1,
...,
názov_stĺpca_n = výraz_n
WHERE booleovský_výraz

Príklad:

UPDATE films
SET price = price * 1.1
WHERE year >= 2015 OR length > 120
Výrazy Výzary v SQL príkazoch

DELETE – Výrazy

DELETE FROM názov_tabuľky


WHERE booleovský_výraz

Príklad:

DELETE FROM films


WHERE price < 10 OR year < 1960
Výrazy Ako sa budujú výrazy

Ako sa budujú výrazy

Výrazy budujeme z:
I názvov stĺpcov a
I literálov
postupným aplikovaním
I operátorov,
I funkcií a
I zátvoriek.
Výrazy Ako sa budujú výrazy

Čísla – operátory

x + y súčet čísel
x - y rozdiel čísel
x * y súčin čísel
Výrazy Ako sa budujú výrazy

Čísla – operátory

x / y podiel čísel

5.0 / 2 = 2.5

Ak sú obe čísla celé, potom je to celočíselné delenie:


I desatinná časť sa zahodí a
I výsledok je celé číslo.

5 / 2 = 2

Delenie nulou?

5 / 0

ERROR: division by zero


Výrazy Ako sa budujú výrazy

Čísla – operátory

x % y modulo (zvyšok po delení)


x ^ y umocnenie (x y )

|/ x druhá odmocnica ( x)

||/ x tretia odmocnica ( 3 x)
Výrazy Ako sa budujú výrazy

Čísla – funkcie

abs(x) absolútna hodnota čísla


ceil(x) zaokrúhli číslo smerom nahor – vráti celé číslo
floor(x) zaokrúhli číslo smerom nadol – vráti celé číslo
.... ...

http:
//www.postgresql.org/docs/current/static/functions-math.html
Výrazy Ako sa budujú výrazy

Operácie a funkcie na číslach a NULL

Ak je jeden z argumentov NULL, výsledok je NULL

5 * NULL → NULL
(5 / NULL) + 1 → NULL

NULL treba chápať ako neznámu hodnotu. Ak niečo spravíme s neznámou


hodnotou, výsledok je neznámy.

0 * NULL → NULL
NULL / 0 → NULL
Výrazy Ako sa budujú výrazy

GREATEST a LEAST

greates(x_1, ..., x_n)

Vráti najväčšiu hodnotu.

least(x_1, ..., x_n)

Vráti najmenšiu hodnotu.

GREATEST a LEAST nie sú klasické funkcie, preto ignorujú NULL


hodnoty. Vrátia NULL iba ak všetky hodnoty sú NULL.
Výrazy Ako sa budujú výrazy

Booleovské výrazy

Sú také výrazy, ktoré sa vyhodnocujú na pravdivostnú hodnotu:


I TRUE – pravda
I FALSE – nepravda
I NULL – neznáma hodnota (nevieme)
Výrazy Ako sa budujú výrazy

Elementárne booleovské výrazy

I TRUE – pravda
I FALSE – nepravda
I NULL – neznáma hodnota (nevieme)
Výrazy Ako sa budujú výrazy

Porovnania

x < y je x menšie ako y?


x <= y je x menšie alebo rovné ako y?
x > y je x väčšie ako y?
x >= y je x väčšie alebo rovné ako y?
x = y rovnajú sa x a y?
x != y nerovnajú sa x a y?

(6 / 2) > (2 + 1)

FALSE
Výrazy Ako sa budujú výrazy

Vstavané dátové typy majú definované usporiadanie <

... < -2 < -1 < 0 < 1 < 2 < ...

.. < DATE ’2016-04-05’ < .. < DATE ’2017-01-01’ < ...

.. < ’a’ < ’ahoj’ < ’b’ < ...

FALSE < TRUE


Výrazy Ako sa budujú výrazy

Porovnávanie s NULL hodnotou

Ak jeden operand porovnávania (<, <=, >, >=, =, !=) je NULL,


výsledok je tiež NULL.

10 = 10 → TRUE
10 != 10 → FALSE
10 = NULL → NULL
NULL = NULL → NULL
NULL != NULL → NULL

NULL treba chápať ako neznámu hodnotu. Ak jeden operand je neznámy,


výsledok je tiež neznámy.
Výrazy Ako sa budujú výrazy

Ako testovať na NULL?

x IS NULL či je x NULL
x IS NOT NULL či x je iné než NULL

10 IS NULL FALSE
NULL IS NULL TRUE

Vždy vráti TRUE alebo FALSE, nikdy NULL.


Výrazy Ako sa budujú výrazy

Niekedy potrebujeme, aby sa dva NULLy rovnali

settings
key actual_value default_value
colour red blue
timeout 10 NULL
max_volume NULL NULL

Ak NULL chápeme ako nezadanú hodnotu, pri kontrole či actual_value je


zhodné s default_value, chceme aby sa NULL hodnoty rovnali
Výrazy Ako sa budujú výrazy

Niekedy potrebujeme, aby sa dva NULLy rovnali

x IS NOT DISTINCT FROM y


I ak x,y nie sú NULL, potom rovnako ako x = y,
I ak x,y sú oba NULL, potom vráti TRUE,
I ak je iba jeden NULL, potom FALSE.

10 IS NOT DISTINCT FROM 10 TRUE


10 IS NOT DISTINCT FROM 20 FALSE
10 IS NOT DISTINCT FROM NULL FALSE
NULL IS NOT DISTINCT FROM NULL TRUE

Vždy vráti TRUE alebo FALSE, nikdy NULL.


Výrazy Ako sa budujú výrazy

Niekedy potrebujeme, aby sa dva NULLy rovnali

x IS DISTINCT FROM y
I ak ani x ani y nie je NULL, potom rovnako ako x != y,
I ak x,y sú oba NULL, potom vráti FALSE,
I ak je iba jeden NULL, potom TRUE.

10 IS DISTINCT FROM 10 FALSE


10 IS DISTINCT FROM 20 TRUE
10 IS DISTINCT FROM NULL TRUE
NULL IS DISTINCT FROM NULL FALSE

Vždy vráti TRUE alebo FALSE, nikdy NULL.


Výrazy Ako sa budujú výrazy

Spájanie booleovských výrazov logickými spojkami

výraz_1 AND výraz_2

výraz_1 OR výraz_2

NOT výraz
Výrazy Ako sa budujú výrazy

3-hodnotová logika – AND

AND

TRUE FALSE NULL


TRUE TRUE FALSE NULL
FALSE FALSE FALSE FALSE
NULL NULL FALSE NULL
Výrazy Ako sa budujú výrazy

3-hodnotová logika – AND – Návod pre NULL

TRUE AND NULL → ?


Výrazy Ako sa budujú výrazy

3-hodnotová logika – AND – Návod pre NULL

TRUE AND NULL → ?


TRUE AND TRUE → TRUE
TRUE AND FALSE → FALSE
Výrazy Ako sa budujú výrazy

3-hodnotová logika – AND – Návod pre NULL

TRUE AND NULL → ?


TRUE AND TRUE → TRUE
TRUE AND FALSE → FALSE

Dostali sme rôzme hodnoty, takže výsledok je NULL


Výrazy Ako sa budujú výrazy

3-hodnotová logika – AND – Návod pre NULL

FALSE AND NULL → ?


FALSE AND TRUE → FALSE
FALSE AND FALSE → FALSE

V oboch prípadoch sme dostali FALSE, takže výsledok je FALSE


Výrazy Ako sa budujú výrazy

3-hodnotová logika – OR

OR

TRUE FALSE NULL


TRUE TRUE TRUE TRUE
FALSE TRUE FALSE NULL
NULL TRUE NULL NULL
Výrazy Ako sa budujú výrazy

3-hodnotová logika – NOT

NOT

TRUE FALSE
FALSE TRUE
NULL NULL
Výrazy Ako sa budujú výrazy

BETWEEN

x BETWEEN y AND z

je ekvivalentné

y <= x AND x <= z


Výrazy Ako sa budujú výrazy

NOT BETWEEN

x NOT BETWEEN y AND z

je ekvivalentné

x < y OR z < x
Výrazy Ako sa budujú výrazy

IN

x IN (y_1, ..., y_n)

je ekvivalentné

x = y_1 OR ... OR x = y_n


Výrazy Ako sa budujú výrazy

NOT IN

x NOT IN (y_1, ..., y_n)

je ekvivalentné

x != y_1 AND ... AND x != y_n


Výrazy Ako sa budujú výrazy

IN/NOT IN – Pozor na NULLy

5 IN (NULL, 6)

5 = NULL OR 5 = 6
NULL OR FALSE
NULL
Výrazy Ako sa budujú výrazy

IN/NOT IN – Pozor na NULLy

5 NOT IN (NULL, 6)

5 != NULL AND 5 != 6
NULL AND TRUE
NULL
WHERE a NULL

Section 7

WHERE a NULL
WHERE a NULL

SELECT, UPDATE, DELETE – WHERE a NULL

WHERE booleovsky_vyraz

I príkaz sa aplikuje iba na riadky, pre ktoré sa výraz vyhodnotí na TRUE,


I na riadky, pre ktoré sa vyhodnotí na FALSE alebo NULL sa príkaz
neaplikuje
WHERE a NULL

SELECT, UPDATE, DELETE – WHERE a NULL

users
id name email country_id
1 fan123 fan123@gmail.com 1
2 johnny spam@spam.com 4
3 stellar stellar@email.com NULL

SELECT id, name, email, country_id


FROM users
WHERE country_id != 1

id name email country_id


2 johnny spam@spam.com 4
WHERE a NULL

SELECT, UPDATE, DELETE – WHERE a NULL

users
id name email country_id
1 fan123 fan123@gmail.com 1
2 johnny spam@spam.com 4
3 stellar stellar@email.com NULL

SELECT id, name, email, country_id


FROM users
WHERE country_id IS DISTINCT FROM 1

id name email country_id


2 johnny spam@spam.com 4
3 stellar stellar@email.com NULL
Default hodnoty stĺpcov

Section 8

Default hodnoty stĺpcov


Default hodnoty stĺpcov

Default hodnota stĺpca

CREATE TABLE názov_tabuľky


(
názov_stĺpca typ DEFAULT výraz
)

Ak default hodnotu neuvedieme, tak default hodnota je NULL


Default hodnoty stĺpcov

Default hodnota stĺpca – Príklad

CREATE TABLE films


(
id INTEGER,
name VARCHAR(100),
year INTEGER,
price NUMERIC DEFAULT 10
)
Default hodnoty stĺpcov

Default hodnota stĺpca – INSERT


Ak pri vkladaní riadku neuvedieme hodnotu stĺpca, vložíme default hodnotu

CREATE TABLE films


(
id INTEGER,
name VARCHAR(100),
year INTEGER,
price NUMERIC DEFAULT 10
)
INSERT INTO films (id, name, year)
VALUES (6, ’Interstellar’, 2014)

id name year price


6 Interstellar 2014 10
Default hodnoty stĺpcov

Default hodnota stĺpca – INSERT


Ak pri vkladaní riadku uvedieme ako hodnotu stĺpca "DEFAULT", vložíme
default hodnotu

CREATE TABLE films


(
id INTEGER,
name VARCHAR(100),
year INTEGER,
price NUMERIC DEFAULT 10
)
INSERT INTO films (id, name, year, price)
VALUES (6, ’Interstellar’, 2014, DEFAULT)

id name year price


6 Interstellar 2014 10
Default hodnoty stĺpcov

Default hodnota stĺpca – UPDATE


Pri aktualizovaní riadku môžeme použitím "DEFAULT" nastaviť stĺpec na
default hodnotu
CREATE TABLE films
(
id INTEGER,
name VARCHAR(100),
year INTEGER,
price NUMERIC DEFAULT 10
)
id name year price
6 Interstellar 2014 8
UPDATE films SET price = DEFAULT
WHERE id = 6
id name year price
6 Interstellar 2014 10
Default hodnoty stĺpcov

Default hodnota stĺpca – Príklad 2

CREATE TABLE user_activities


(
user_id INTEGER,
activity VARCHAR(100),
time TIMESTAMP DEFAULT now()
)
Default hodnoty stĺpcov

Default hodnota stĺpca – Nemôžeme referencovať iný stĺpec

CREATE TABLE test


(
a INTEGER,
b INTEGER DEFAULT a + 10
)

ERROR: cannot use column references in


default expression
Sekvencie a automaticky inkrementované čísla

Section 9

Sekvencie a automaticky inkrementované čísla


Sekvencie a automaticky inkrementované čísla

Sekvencia

I je databázový object – podobne ako tabuľka existuje v databáze


I slúži na získavanie čísel v postupnosti
Sekvencie a automaticky inkrementované čísla

CREATE SEQUENCE

CREATE SEQUENCE nazov_sekvencie

I vytvorí sekvenciu s daným názvom


I počiatočná hodnota sekvencie je 1
I syntax je bohatšia, my si vystačíme s týmto
Sekvencie a automaticky inkrementované čísla

DROP SEQUENCE

DROP SEQUENCE nazov_sekvencie

I zmaže sekvenciu s daným názvom


Sekvencie a automaticky inkrementované čísla

Funkcia nextval

nextval(nazov_sekvencie)

I vráti ďalšiu nepoužitú hodnotu sekvencie


I názov sekvencie v apostrofoch
Sekvencie a automaticky inkrementované čísla

Príklad

CREATE SEQUENCE my_sequence;

nexval(’my_sequence’) -> vráti 1


nexval(’my_sequence’) -> vráti 2
nexval(’my_sequence’) -> vráti 3
Sekvencie a automaticky inkrementované čísla

Automaticky inkrementované idčka

CREATE SEQUENCE id_seq;

CREATE TABLE films


(
id integer DEFAULT nextval(’id_seq’),
name varchar
);

INSERT INTO films (name) VALUES


(’Léon: The Professional’),
(’Django Unchained’);
films
id name
1 Léon: The Professional
2 Django Unchained
Sekvencie a automaticky inkrementované čísla

Syntaktický cukor – dátový typ serial

CREATE TABLE films


(
id serial,
name varchar
);

PostgreSQL za vás na pozadí nahradí za

CREATE SEQUENCE id_seq;

CREATE TABLE films


(
id integer DEFAULT nextval(’id_seq’),
name varchar
);
Sekvencie a automaticky inkrementované čísla

Syntaktický cukor – dátový typ serial

CREATE TABLE films


(
id serial
name varchar
);

INSERT INTO films (name) VALUES


(’Léon: The Professional’),
(’Django Unchained’);

films
id name
1 Léon: The Professional
2 Django Unchained
SELECT podrobnejšie

Section 10

SELECT podrobnejšie
SELECT podrobnejšie SELECT bez FROM

SELECT bez FROM

SELECT môžeme použiť aj bez FROM časti:

SELECT výraz_1, ..., výraz_n

Výsledkom je jeden riadok.


SELECT podrobnejšie SELECT bez FROM

SELECT bez FROM – Príklad

SELECT 5 * (9 - 3) > 15

?column?
t
SELECT podrobnejšie Aliasy stĺpcov

Aliasy stĺpcov

SELECT 5 * (9 - 3) > 15

?column?
t

Ak vyberáme zložený výraz, stĺpec sa bude volať ’ ?column?’


SELECT podrobnejšie Aliasy stĺpcov

Aliasy stĺpcov – Syntax

výraz AS alias_stĺpca
SELECT podrobnejšie Aliasy stĺpcov

Aliasy stĺpcov – Príklad

SELECT name, price * 1.1 AS new_price FROM films

name new_price
Léon: The Professional 11
Django Unchained 12
SELECT podrobnejšie Aliasy stĺpcov

Aliasy stĺpcov – Príklad 2

Niekedy potrebujeme pomenovať sĺpce niečim čitateľným pre koncového


používateľa:

SELECT first_name AS "First name",


last_name AS "Last name"
FROM employees
SELECT podrobnejšie Aliasy stĺpcov

Aliasy stĺpcov – Pozor

Alias stĺpca nemôžeme použiť vo výraze


SELECT name,
price * 1.1 AS new_price,
new_price * 2
FROM films

ERROR: column "new_price" does not exist


SELECT podrobnejšie Aliasy stĺpcov

Aliasy stĺpcov – Použitie už existujúceho názvu

Na ľavej strane od kľúčového slova AS je vždy pôvodný stĺpec


SELECT name,
price,
price * 1.1 AS price,
price * 2
FROM films

name price price ?column?


Léon: The Professional 10 11 20
Django Unchained 10 11 20
SELECT podrobnejšie Aliasy stĺpcov

Aliasy stĺpcov – Použitie už existujúceho názvu

Na ľavej strane od kľúčového slova AS je vždy pôvodný stĺpec


SELECT name,
price,
price * 1.1 AS price,
price * 2
FROM films

name price price ?column?


Léon: The Professional 10 11 20
Django Unchained 10 11 20

Vo výsledku SELECTu môžu mať dva stĺpce rovnaký názov.


SELECT podrobnejšie Pseudostĺpec *

Pseudostĺpec *

Hviezdička vyberie všetky stĺpce v poradí v akom boli definované

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10

SELECT * FROM films

id name year price


1 Léon: The Professional 1994 10
2 Django Unchained 2012 10
SELECT podrobnejšie Pseudostĺpec *

Pseudostĺpec *

Môžeme ešte zvoliť ďalšie výrazy

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10

SELECT *, year FROM films

id name year price year


1 Léon: The Professional 1994 10 1994
2 Django Unchained 2012 10 2012
SELECT podrobnejšie ORDER BY

SELECT štandardne negarantuje poradie vrátených riadkov

I riadky ale nie sú v náhodnom poradí


I je dané tým ako sú uložené na disku, použitými algoritmami a stavom
dátových štruktúr v databázovom systéme
I ak spustíme po sebe 2x ten istý SELECT bez toho, aby sme medzi tým
spravili niečo iné, pravdepodobne dostaneme riadky v tom istom poradí
SELECT podrobnejšie ORDER BY

ORDER BY – Syntax

I riadky môžeme usporiadať pomocou ORDER BY klauzuly


I ORDER BY sa uvádza za WHERE

ORDER BY výraz_1 [ASC | DESC] [NULLS FIRST | NULLS LAST],


...
výraz_n [ASC | DESC] [NULLS FIRST | NULLS LAST]
SELECT podrobnejšie ORDER BY

ORDER BY – Sémantika

ORDER BY výraz_1, výraz_2, ..., výraz_n

usporiada riadky lexikograficky:


1. najprv sa riadky usporiadajú podľa výrazu_1
2. riadky, ktoré sa zhodujú v hodnotách výrazu_1 sa usporiadajú podľa
výrazu_2
3. riadky, ktoré sa zhodujú v hodnotách výrazu_1 aj výrazu_2, sa
usporiadajú podľa výrazu_3
4. atď.
SELECT podrobnejšie ORDER BY

ORDER BY

ASC
I riadky sa podľa daného výrazu usporiadajú vzostupne,
I od najmenšieho po najväčší
I default,

DESC
I riadky sa podľa daného výrazu usporiadajú zostupne
I od najväčšieho po najmenší.
SELECT podrobnejšie ORDER BY

ORDER BY – Príklad

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10
3 Unbreakable 2000 8
4 Seven Samurai 1954 NULL

SELECT * FROM films


ORDER BY year < 2000 DESC, name ASC
SELECT podrobnejšie ORDER BY

ORDER BY – Príklad

SELECT * FROM films


ORDER BY year < 2000 DESC, name ASC

id name year price


1 Léon: The Professional 1994 10
4 Seven Samurai 1954 NULL
2 Django Unchained 2012 10
3 Unbreakable 2000 8

I year < 2000 sa vyhodnotí na true/false


I year < 2000 DESC – najprv pôjdu riadky kde sa výraz year < 2000
vyhodnotí na true
I name – riadky, pre ktoré sa year < 2000 vyhodnotí rovnako, sa
usporiadajú podľa name
SELECT podrobnejšie ORDER BY

Pri usporiadaní sa NULL hodnoty považujú za rovnaké

SELECT * FROM films


ORDER price, year

id name year price


3 Unbreakable 2000 8
2 Django Unchained 2012 10
4 Seven Samurai 1954 NULL
6 Bram Stocker’s Dracula 1992 NULL
1 Léon: The Professional 1994 NULL
SELECT podrobnejšie ORDER BY

Pri usporiadaní sa NULL hodnoty považujú za rovnaké

SELECT * FROM films


ORDER price, year

id name year price


3 Unbreakable 2000 8
2 Django Unchained 2012 10
4 Seven Samurai 1954 NULL
6 Bram Stocker’s Dracula 1992 NULL
1 Léon: The Professional 1994 NULL

Ak by to tak nebolo, potom posledné tri riadky mohli byť v ľubovoľnom


poradí.
SELECT podrobnejšie ORDER BY

ORDER BY

NULLS LAST
I riadky majúce daný výraz NULLový pôjdu na koniec
I default pre ASC

NULLS FIRST
I riadky majúce daný výraz NULLový pôjdu na začiatok
I default pre DESC
SELECT podrobnejšie ORDER BY

ORDER BY – Príklad 2

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10
3 Unbreakable 2000 8
4 Seven Samurai 1954 NULL

SELECT * FROM films


ORDER BY price DESC NULLS FIRST

id name year price


4 Seven Samurai 1954 NULL
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10
3 Unbreakable 2000 8
SELECT podrobnejšie ORDER BY

ORDER BY – Príklad 3

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10
3 Unbreakable 2000 8
4 Seven Samurai 1954 NULL

SELECT * FROM films


ORDER BY price DESC NULLS LAST

id name year price


1 Léon: The Professional 1994 10
2 Django Unchained 2012 10
3 Unbreakable 2000 8
4 Seven Samurai 1954 NULL
SELECT podrobnejšie LIMIT a OFFSET

LIMIT

LIMIT číslo

I píše sa za ORDER BY
I obmedzí počet výsledkov na maximálne daný počet
I menej výsledkov bude iba ak samotný SELECT vráti menej riadkov

LIMIT ALL
LIMIT NULL

I nijako neobmedzí počet výsledkov


I akokeby sme ani neuviedli
SELECT podrobnejšie LIMIT a OFFSET

LIMIT – Príklad

Tri najstaršie filmy


SELECT name
FROM films
ORDER BY year ASC
LIMIT 3
SELECT podrobnejšie LIMIT a OFFSET

OFFSET

OFFSET číslo

I píše sa za ORDER BY
I preskočí daný počet riadkov

OFFSET 0
OFFSET NULL

I preskočí 0 riadkov
I akokeby sme ani neuviedli
SELECT podrobnejšie LIMIT a OFFSET

OFFSET – Príklad

Tretí až piaty najstarší film


SELECT name
FROM films
ORDER BY year ASC
OFFSET 2 LIMIT 3
SELECT podrobnejšie LIMIT a OFFSET

Stránkovanie pomocou LIMIT a OFFSET

Ak máme veľa riadkov v tabuľke, nechceme zvyčajne zobraziť všetky naraz


ale po stránkach.

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10
3 Unbreakable 2000 8
4 Seven Samurai 1954 NULL
5 El mariachi 1992 7
6 Bram Stocker’s Dracula 1992 8
SELECT podrobnejšie LIMIT a OFFSET

Stránkovanie pomocou LIMIT a OFFSET

Ak má stránka veľkosť n = 2, riadky sú rozdelené nasledovne:

1 Léon: The Professional 1994 10


0
2 Django Unchained 2012 10

3 Unbreakable 2000 8
1
4 Seven Samurai 1954 NULL

5 El mariachi 1992 7
2
6 Bram Stocker’s Dracula 1992 8

Aby sme dostali i-tu stránku, musíme preskočiť i ∗ n riadkov.


SELECT podrobnejšie LIMIT a OFFSET

Stránkovanie pomocou LIMIT a OFFSET

i-tu stránku získame príkazom


SELECT *
FROM nazov_tabulky
OFFSET i*n LIMIT n
SELECT podrobnejšie LIMIT a OFFSET

LIMIT a OFFSET a nejednoznačné poradie riadkov

Ak poradie riadkov nie je jednoznačné, tak nie je garantované, ktoré riadky


pri použití LIMIT a OFFSET dostaneme. Zakaždým môžeme dostať iné.

Poradie nie je jednoznačné, keď:


I nepoužijeme ORDER BY
I máme riadky, ktoré sú z pohľadu ORDER BY rovnaké
SELECT podrobnejšie DISTINCT

SELECT štandardne duplicity neodstraňuje

films
id name year price
1 Léon: The Professional 1994 10
3 Pulp Fiction 1994 10
7 Interview with the Vampire 1994 9

Pre každý rok výroby filmu chceme získať ceny filmov.


SELECT year, price
FROM films
year price
1994 10
1994 10
1994 9

Čo ak ale nechceme duplicitné riadky?


SELECT podrobnejšie DISTINCT

DISTINCT odstráni duplicitné riadky

films
id name year price
1 Léon: The Professional 1994 10
3 Pulp Fiction 1994 10
7 Interview with the Vampire 1994 9

SELECT DISTINCT year, price


FROM films

year price
1994 10
1994 9
SELECT podrobnejšie DISTINCT

DISTINCT iba podľa niektorých stĺpcov?

films
id name year price
1 Léon: The Professional 1994 10
3 Pulp Fiction 1994 10
7 Interview with the Vampire 1994 9

SELECT DISTINCT year, price


FROM films

year price
1994 10
1994 9

Čo ak by sme chceli za každý rok iba jednu cenu?


SELECT podrobnejšie DISTINCT

DISTINCT ON

SELECT DISTINCT ON (d_vyraz_1, ..., d_vyraz_n) ...

I riadky duplicitné vo výrazoch d_vyraz_1, ..., d_vyraz_n sú


odstránené
SELECT podrobnejšie DISTINCT

DISTINCT ON

films
id name year price
1 Léon: The Professional 1994 10
3 Pulp Fiction 1994 10
7 Interview with the Vampire 1994 9

SELECT DISTINCT ON (year) year, price


FROM films

year price
1994 10
SELECT podrobnejšie DISTINCT

Výrazy v DISTINCT ON a SELECT sa nemusia zhodovať

films
id name year price
1 Léon: The Professional 1994 10
3 Pulp Fiction 1994 10
7 Interview with the Vampire 1994 9

SELECT DISTINCT ON (year) name


FROM films

name
Léon: The Professional
SELECT podrobnejšie DISTINCT

DISTINCT pomocou DISTINCT ON

SELECT DISTINCT vyraz_1, ..., vyraz_n


FROM nazov_tabulky

je to isté ako

SELECT DISTINCT ON (vyraz_1, ..., vyraz_n)


vyraz_1, ..., vyraz_n
FROM nazov_tabulky

čiže DISTINCT je len syntaktický cukor


SELECT podrobnejšie DISTINCT

DISTINCT ON považuje NULL hodnoty za rovnaké

films
id name year price
1 Léon: The Professional NULL 10
3 Pulp Fiction NULL 10
7 Interview with the Vampire NULL 9

SELECT DISTINCT ON (year) name


FROM films

name
Léon: The Professional
SELECT podrobnejšie DISTINCT

Ako sa odstráňujú duplicity?

SELECT DISTINCT ON (d_vyraz_1, ..., d_vyraz_n) ...

I Riadky sa usporiadajú podľa d_vyraz_1, ..., d_vyraz_n


I Tým pádom riadky, ktoré majú rovnaké hodnoty výrazov d_vyraz_1,
..., d_vyraz_n sú za sebou
I Iterujeme a porovnávame riadok s predchádzajúcim. Ak sú rovnaké, do
výstupu ho nedávame.
SELECT podrobnejšie DISTINCT

Ako sa odstráňujú duplicity?

films
id name year price
1 Léon: The Professional 1994 10
3 Pulp Fiction 1994 10
5 El mariachi 1992 7
7 Interview with the Vampire 1994 9
6 Bram Stocker’s Dracula 1992 8

SELECT DISTINCT ON (year) year, price


FROM films
SELECT podrobnejšie DISTINCT

Ako sa odstráňujú duplicity?

Riadky sa usporiadajú podľa year

id name year price


5 El mariachi 1992 7
6 Bram Stocker’s Dracula 1992 8
1 Léon: The Professional 1994 10
3 Pulp Fiction 1994 10
7 Interview with the Vampire 1994 9
SELECT podrobnejšie DISTINCT

Ako sa odstráňujú duplicity?

Iterujeme riadkami a kontrolujeme year

id name year price


5 El mariachi 1992 7
6 Bram Stocker’s Dracula 1992 8
1 Léon: The Professional 1994 10
3 Pulp Fiction 1994 10
7 Interview with the Vampire 1994 9
SELECT podrobnejšie DISTINCT

Ako sa odstráňujú duplicity?

Iterujeme riadkami a kontrolujeme year

id name year price


5 El mariachi 1992 7
6 Bram Stocker’s Dracula 1992 8
1 Léon: The Professional 1994 10
3 Pulp Fiction 1994 10
7 Interview with the Vampire 1994 9

year je rôzny než v predchádzajúcom riadku


SELECT podrobnejšie DISTINCT

Ako sa odstráňujú duplicity?

Iterujeme riadkami a kontrolujeme year

id name year price


5 El mariachi 1992 7
6 Bram Stocker’s Dracula 1992 8
1 Léon: The Professional 1994 10
3 Pulp Fiction 1994 10
7 Interview with the Vampire 1994 9

year je rovnaký ako v predchádzajúcom riadku


SELECT podrobnejšie DISTINCT

Ako sa odstráňujú duplicity?

Iterujeme riadkami a kontrolujeme year

id name year price


5 El mariachi 1992 7
1 Léon: The Professional 1994 10
3 Pulp Fiction 1994 10
7 Interview with the Vampire 1994 9
SELECT podrobnejšie DISTINCT

Ako sa odstráňujú duplicity?

Iterujeme riadkami a kontrolujeme year

id name year price


5 El mariachi 1992 7
1 Léon: The Professional 1994 10
3 Pulp Fiction 1994 10
7 Interview with the Vampire 1994 9

year je rôzny než v predchádzajúcom riadku


SELECT podrobnejšie DISTINCT

Ako sa odstráňujú duplicity?

Iterujeme riadkami a kontrolujeme year

id name year price


5 El mariachi 1992 7
1 Léon: The Professional 1994 10
3 Pulp Fiction 1994 10
7 Interview with the Vampire 1994 9

year je rovnaký ako v predchádzajúcom riadku


SELECT podrobnejšie DISTINCT

Ako sa odstráňujú duplicity?

Iterujeme riadkami a kontrolujeme year

id name year price


5 El mariachi 1992 7
1 Léon: The Professional 1994 10
7 Interview with the Vampire 1994 9
SELECT podrobnejšie DISTINCT

Ako sa odstráňujú duplicity?

Iterujeme riadkami a kontrolujeme year

id name year price


5 El mariachi 1992 7
1 Léon: The Professional 1994 10
7 Interview with the Vampire 1994 9

year je rovnaký ako v predchádzajúcom riadku


SELECT podrobnejšie DISTINCT

Ako sa odstráňujú duplicity?

Iterujeme riadkami a kontrolujeme year

id name year price


5 El mariachi 1992 7
1 Léon: The Professional 1994 10
SELECT podrobnejšie DISTINCT

DISTINCT ON a ORDER BY

Na základe toho ako PostgreSQL implementuje DISTINCT ON,

musí byť zoznam DISTINCT ON prefixom zoznamu ORDER BY

SELECT DISTINCT ON (vyraz_1, ...., vyraz_m)


...
ORDER BY vyraz_1, ...., vyraz_m, vyraz_m+1, ..., vyraz_n
SELECT podrobnejšie Rekapitulácia

SELECT – Rekapitulácia

SELECT DISTINCT ON (...) zoznam_výrazov


FROM názov_tabuľky
WHERE boolovský_výraz
ORDER BY order_by_zoznam
LIMIT limit_výraz
OFFSET offset_výraz

1. vezmi tabuľku uvedenú vo FROM časti


2. vyber riadky, ktoré spĺňajú WHERE podmienku
3. zostávajúce riadky usporiadaj podľa ORDER BY klauzy
4. vyhoď duplicity (na základe výrazov v DISTINCT ON časti)
5. pre každý riadok nechaj iba výrazy v SELECT časti
6. každý riadok dostane poradové číslo
7. na základe LIMIT a OFFSET vyber riadky s požadovaným poradovým
číslom
JOIN - Získavanie dát z viacerých tabuliek spájaním

Section 11

JOIN - Získavanie dát z viacerých tabuliek spájaním


JOIN - Získavanie dát z viacerých tabuliek spájaním INNER JOIN

INNER JOIN – motivácia

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10

ratings
user_id film_id rating
1 1 10
2 1 8
2 2 9

Chceme získať hodnotenia filmov, ale namiesto idčka filmu chceme získať
názov filmu.
JOIN - Získavanie dát z viacerých tabuliek spájaním INNER JOIN

INNER JOIN

Kombinuje dve tabuľky do jednej, ktorú môžeme použiť v časti FROM:


názov_tabuĺky_1 INNER JOIN názov_tabuľky_2
ON podmienka

1. vytvor kartézsky súčin tabuliek


I každý riadok z prvej tabuľky spoj s každým riadkom druhej tabuľky
2. vyber dvojice, pre ktoré je splnená podmienka (vyhodnotí sa na TRUE)
JOIN - Získavanie dát z viacerých tabuliek spájaním INNER JOIN

INNER JOIN – Príklad

ratings
films
user_id film_id rating
id name year price
1 1 10
1 Léon 1994 10
2 1 8
2 Django 2012 10
2 2 9

SELECT name, rating


FROM ratings INNER JOIN films
ON film_id = id
JOIN - Získavanie dát z viacerých tabuliek spájaním INNER JOIN

INNER JOIN – Príklad


ratings
films
user_id film_id rating
id name year price
1 1 10
1 Léon 1994 10
2 1 8
2 Django 2012 10
2 2 9
SELECT name, rating
FROM ratings INNER JOIN films
ON film_id = id
user_id film_id rating id name year price
1 1 10 1 Léon 1994 10
1 1 10 2 Django 2012 10
2 1 8 1 Léon 1994 10
2 1 8 2 Django 2012 10
2 2 9 1 Léon 1994 10
2 2 9 2 Django 2012 10
JOIN - Získavanie dát z viacerých tabuliek spájaním INNER JOIN

INNER JOIN – Príklad


ratings
films
user_id film_id rating
id name year price
1 1 10
1 Léon 1994 10
2 1 8
2 Django 2012 10
2 2 9
SELECT name, rating
FROM ratings INNER JOIN films
ON film_id = id
user_id film_id rating id name year price
1 1 10 1 Léon 1994 10
1 1 10 2 Django 2012 10
2 1 8 1 Léon 1994 10
2 1 8 2 Django 2012 10
2 2 9 1 Léon 1994 10
2 2 9 2 Django 2012 10
JOIN - Získavanie dát z viacerých tabuliek spájaním INNER JOIN

INNER JOIN – Príklad

ratings
films
user_id film_id rating
id name year price
1 1 10
1 Léon 1994 10
2 1 8
2 Django 2012 10
2 2 9

SELECT name, rating


FROM ratings INNER JOIN films
ON film_id = id

user_id film_id rating id name year price


1 1 10 1 Léon 1994 10
2 1 8 1 Léon 1994 10
2 2 9 2 Django 2012 10
JOIN - Získavanie dát z viacerých tabuliek spájaním INNER JOIN

INNER JOIN – Príklad

ratings
films
user_id film_id rating
id name year price
1 1 10
1 Léon 1994 10
2 1 8
2 Django 2012 10
2 2 9

SELECT name, rating


FROM ratings INNER JOIN films
ON film_id = id

name rating
Léon 10
Léon 8
Django 9
JOIN - Získavanie dát z viacerých tabuliek spájaním INNER JOIN

INNER JOIN – Na poradí tabuliek takmer nezáleží

Rovnaké výsledky až na poradie stĺpcov


SELECT *
FROM ratings INNER JOIN films
ON film_id = id

user_id film_id rating id name year price

SELECT *
FROM films INNER JOIN ratings
ON film_id = id

id name year price user_id film_id rating


JOIN - Získavanie dát z viacerých tabuliek spájaním INNER JOIN

INNER JOIN – ’INNER’ je nepovinné

názov_tabuľky_1 INNER JOIN názov_tabuľky_2


ON podmienka

je to isté ako
názov_tabuľky_1 JOIN názov_tabuľky_2
ON podmienka
JOIN - Získavanie dát z viacerých tabuliek spájaním Rovnomenné stĺpce

Rovnomenné stĺpce

users
id name email country_id
1 fan123 fan123@gmail.com 1
2 johnny spam@spam.com 4

countries
id name
1 Slovakia
4 Czech Republic

SELECT *
FROM users INNER JOIN countries
ON country_id = id

ERROR: column reference "id" is ambiguous


JOIN - Získavanie dát z viacerých tabuliek spájaním Rovnomenné stĺpce

Rozlišovanie stĺpcov – Syntax

Pred názov stĺpca treba predradiť názov tabuľky:

názov_tabuľky.názov_stĺpca
JOIN - Získavanie dát z viacerých tabuliek spájaním Rovnomenné stĺpce

Rozlišovanie stĺpcov – Príklad

SELECT *
FROM users INNER JOIN countries
ON country_id = countries.id

id name email country_id id name


1 fan123 fan123@gmail.com 1 1 Slovakia
2 johnny spam@spam.com 4 4 Czech Republic
JOIN - Získavanie dát z viacerých tabuliek spájaním Rovnomenné stĺpce

Všetky stĺpce konkrétnej tabuľky

I * vyberá všetky stĺpce všetkých tabuliek, ktoré sa spájali


I názov_tabuľky.* vyberie všetky stĺpce konkrétnej tabuľky
JOIN - Získavanie dát z viacerých tabuliek spájaním Rovnomenné stĺpce

Všetky stĺpce konkrétnej tabuľky – Príklad

SELECT users.*, countries.name


FROM users INNER JOIN countries
ON country_id = countries.id

id name email country_id name


1 fan123 fan123@gmail.com 1 Slovakia
2 johnny spam@spam.com 4 Czech Republic
JOIN - Získavanie dát z viacerých tabuliek spájaním OUTER JOIN

OUTER JOIN – motivácia

users
countries
id name email country_id
id name
1 fan123 fan123@gmail.com 1
1 Slovakia
2 johnny spam@spam.com 4
4 Czech Republic
3 stellar my@email.ch NULL

SELECT user.name, country.name


FROM users INNER JOIN countries
ON country_id = countries.id
JOIN - Získavanie dát z viacerých tabuliek spájaním OUTER JOIN

OUTER JOIN – motivácia

Používateľ s idčkom 3 vypadne, lebo countries.id = NULL sa nevyhodnotí


na TRUE pre žiadnu dvojicu.

id name email country_id id name


1 fan123 fan123@gmail.com 1 1 Slovakia
2 johnny spam@spam.com 4 4 Czech Republic

Čo ak by sme chceli používateľa 3 nechať a na miesto názvu krajiny dať


NULL?
JOIN - Získavanie dát z viacerých tabuliek spájaním LEFT OUTER JOIN

LEFT OUTER JOIN

Kombinuje dve tabuľky do jednej, ktorú môžeme použiť v časti FROM:

názov_tabuĺky_1 LEFT OUTER JOIN názov_tabuľky_2


ON podmienka

Pre každý riadok tabuľky_1


1. pripoj každý riadok z tabuľky_2 taký, že je podmienka splnená,
2. ak žiaden taký riadok neexistuje, stĺpce z tabuľky_2 vyplň NULLmi

Vo výsledku sú všetky riadky tabuľky_1.


JOIN - Získavanie dát z viacerých tabuliek spájaním LEFT OUTER JOIN

LEFT OUTER JOIN – Príklad

users
countries
id name email country_id
id name
1 fan123 fan123@gmail.com 1
1 Slovakia
2 johnny spam@spam.com 4
4 Czech Republic
3 stellar my@email.ch NULL

SELECT users.name, countries.name


FROM users LEFT OUTER JOIN countries
ON country_id = countries.id
JOIN - Získavanie dát z viacerých tabuliek spájaním LEFT OUTER JOIN

LEFT OUTER JOIN – Príklad


users
countries
id name email country_id
id name
1 fan123 fan123@gmail.com 1
1 Slovakia
2 johnny spam@spam.com 4
4 Czech Republic
3 stellar my@email.ch NULL
SELECT users.name, countries.name
FROM users LEFT OUTER JOIN countries
ON country_id = countries.id
id name email country_id id name
1 fan123 fan123@gmail.com 1 1 Slovakia
1 fan123 fan123@gmail.com 1 4 Czech Republic
2 johnny spam@spam.com 4 1 Slovakia
2 johnny spam@spam.com 4 4 Czech Republic
3 stellar my@email.ch NULL 1 Slovakia
3 stellar my@email.ch NULL 4 Czech Republic
JOIN - Získavanie dát z viacerých tabuliek spájaním LEFT OUTER JOIN

LEFT OUTER JOIN – Príklad


users
countries
id name email country_id
id name
1 fan123 fan123@gmail.com 1
1 Slovakia
2 johnny spam@spam.com 4
4 Czech Republic
3 stellar my@email.ch NULL
SELECT users.name, countries.name
FROM users LEFT OUTER JOIN countries
ON country_id = countries.id
id name email country_id id name
1 fan123 fan123@gmail.com 1 1 Slovakia
1 fan123 fan123@gmail.com 1 4 Czech Republic
2 johnny spam@spam.com 4 1 Slovakia
2 johnny spam@spam.com 4 4 Czech Republic
3 stellar my@email.ch NULL 1 Slovakia
3 stellar my@email.ch NULL 4 Czech Republic
JOIN - Získavanie dát z viacerých tabuliek spájaním LEFT OUTER JOIN

LEFT OUTER JOIN – Príklad

users
countries
id name email country_id
id name
1 fan123 fan123@gmail.com 1
1 Slovakia
2 johnny spam@spam.com 4
4 Czech Republic
3 stellar my@email.ch NULL

SELECT users.name, countries.name


FROM users LEFT OUTER JOIN countries
ON country_id = countries.id

id name email country_id id name


1 fan123 fan123@... 1 1 Slovakia
2 johnny spam@... 4 4 Czech Republic
3 stellar my@... NULL NULL NULL
JOIN - Získavanie dát z viacerých tabuliek spájaním LEFT OUTER JOIN

LEFT OUTER JOIN – Príklad

users
countries
id name email country_id
id name
1 fan123 fan123@gmail.com 1
1 Slovakia
2 johnny spam@spam.com 4
4 Czech Republic
3 stellar my@email.ch NULL

SELECT users.name, countries.name


FROM users LEFT OUTER JOIN countries
ON country_id = countries.id

name name
fan123 Slovakia
johnny Czech Republic
stellar NULL
JOIN - Získavanie dát z viacerých tabuliek spájaním LEFT OUTER JOIN

LEFT OUTER JOIN – ’OUTER’ je nepovinné

názov_tabuĺky_1 LEFT OUTER JOIN názov_tabuľky_2


ON podmienka

je to isté ako

názov_tabuĺky_1 LEFT JOIN názov_tabuľky_2


ON podmienka
JOIN - Získavanie dát z viacerých tabuliek spájaním RIGHT OUTER JOIN

RIGHT OUTER JOIN

To isté ako LEFT OUTER JOIN až na poradie tabuliek a stĺpcov

názov_tabuĺky_1 RIGHT OUTER JOIN názov_tabuľky_2


ON podmienka

Pre každý riadok tabuľky_2


1. pripoj každý riadok z tabuľky_1 taký, že je podmienka splnená,
2. ak žiaden taký riadok neexistuje, stĺpce z tabuľky_1 vyplň NULLmi

Vo výsledku sú všetky riadky tabuľky_2


JOIN - Získavanie dát z viacerých tabuliek spájaním RIGHT OUTER JOIN

RIGHT OUTER JOIN – Príklad

countries
users
id name
id name email country_id
1 Slovakia
1 fan123 fan123@gmail.com 1
4 Czech Republic
2 johnny spam@spam.com 4
5 Poland

SELECT users.name, countries.name


FROM users RIGHT OUTER JOIN countries
ON country_id = countries.id
JOIN - Získavanie dát z viacerých tabuliek spájaním RIGHT OUTER JOIN

RIGHT OUTER JOIN – Príklad


countries
users
id name
id name email country_id
1 Slovakia
1 fan123 fan123@gmail.com 1
4 Czech Republic
2 johnny spam@spam.com 4
5 Poland
SELECT users.name, countries.name
FROM users RIGHT OUTER JOIN countries
ON country_id = countries.id
id name email country_id id name
1 fan123 fan123@... 1 1 Slovakia
2 johnny spam@... 4 1 Slovakia
1 fan123 fan123@... 1 4 Czech Republic
2 johnny spam@... 4 4 Czech Republic
1 fan123 fan123@... 1 5 Poland
2 johnny spam@... 4 5 Poland
JOIN - Získavanie dát z viacerých tabuliek spájaním RIGHT OUTER JOIN

RIGHT OUTER JOIN – Príklad


countries
users
id name
id name email country_id
1 Slovakia
1 fan123 fan123@gmail.com 1
4 Czech Republic
2 johnny spam@spam.com 4
5 Poland
SELECT users.name, countries.name
FROM users RIGHT OUTER JOIN countries
ON country_id = countries.id
id name email country_id id name
1 fan123 fan123@... 1 1 Slovakia
2 johnny spam@... 4 1 Slovakia
1 fan123 fan123@... 1 4 Czech Republic
2 johnny spam@... 4 4 Czech Republic
1 fan123 fan123@... 1 5 Poland
2 johnny spam@... 4 5 Poland
JOIN - Získavanie dát z viacerých tabuliek spájaním RIGHT OUTER JOIN

RIGHT OUTER JOIN – Príklad

countries
users
id name
id name email country_id
1 Slovakia
1 fan123 fan123@gmail.com 1
4 Czech Republic
2 johnny spam@spam.com 4
5 Poland

SELECT users.name, countries.name


FROM users RIGHT OUTER JOIN countries
ON country_id = countries.id

id name email country_id id name


1 fan123 fan123@... 1 1 Slovakia
2 johnny spam@... 4 4 Czech Republic
NULL NULL NULL NULL 5 Poland
JOIN - Získavanie dát z viacerých tabuliek spájaním RIGHT OUTER JOIN

RIGHT OUTER JOIN – Príklad

countries
users
id name
id name email country_id
1 Slovakia
1 fan123 fan123@gmail.com 1
4 Czech Republic
2 johnny spam@spam.com 4
5 Poland

SELECT users.name, countries.name


FROM users RIGHT OUTER JOIN countries
ON country_id = countries.id

name name
fan123 Slovakia
johnny Czech Republic
NULL Poland
JOIN - Získavanie dát z viacerých tabuliek spájaním RIGHT OUTER JOIN

RIGHT OUTER JOIN – ’OUTER’ je nepovinné

názov_tabuĺky_1 RIGHT OUTER JOIN názov_tabuľky_2


ON podmienka

je to isté ako

názov_tabuĺky_1 RIGHT JOIN názov_tabuľky_2


ON podmienka
JOIN - Získavanie dát z viacerých tabuliek spájaním FULL OUTER JOIN

FULL OUTER JOIN

Kombinácia LEFT a RIGHT OUTER JOINov

názov_tabuĺky_1 FULL OUTER JOIN názov_tabuľky_2


ON podmienka

1. riadky z tabuľky_1 spojí s riadkami z tabuľky_2 tak, že je splnená


podmienka,
2. ak pre riadok z jednej tabuľky žiaden riadok z druhej tabuľky nespĺňa
podmienku, chýbajúce stĺpce vyplní NULLmi

Vo výsledku sú všetky riadky oboch tabuliek.


JOIN - Získavanie dát z viacerých tabuliek spájaním FULL OUTER JOIN

FULL OUTER JOIN – Príklad

Zoznam používateľov s názvami krajím:


I ponechať používateľov s nezadanou krajinou,
I pridať prázdne krajiny

users countries
id name email country_id id name
1 fan123 fan123@gmail.com 1 1 Slovakia
2 johnny spam@spam.com 4 4 Czech Republic
3 stellar my@email.ch NULL 5 Poland
JOIN - Získavanie dát z viacerých tabuliek spájaním FULL OUTER JOIN

FULL OUTER JOIN – Príklad

users countries
id name email country_id id name
1 fan123 fan123@gmail.com 1 1 Slovakia
2 johnny spam@spam.com 4 4 Czech Republic
3 stellar my@email.ch NULL 5 Poland

SELECT *
FROM users FULL OUTER JOIN countries
ON country_id = countries.id

id name email country_id id name


1 fan123 fan123@... 1 1 Slovakia
2 johnny spam@... 4 4 Czech Republic
3 stellar my@... NULL NULL NULL
NULL NULL NULL NULL 5 Poland
JOIN - Získavanie dát z viacerých tabuliek spájaním FULL OUTER JOIN

FULL OUTER JOIN – ’OUTER’ je nepovinné

názov_tabuĺky_1 FULL OUTER JOIN názov_tabuľky_2


ON podmienka

je to isté ako

názov_tabuĺky_1 FULL JOIN názov_tabuľky_2


ON podmienka
JOIN - Získavanie dát z viacerých tabuliek spájaním CROSS JOIN

CROSS JOIN – Syntax

Kombinuje dve tabuľky do jednej, ktorú môžeme použiť v časti FROM:

názov_tabuĺky_1 CROSS JOIN názov_tabuľky_2

1. vytvorí kartézsky súčin tabuliek


JOIN - Získavanie dát z viacerých tabuliek spájaním CROSS JOIN

CROSS JOIN – Príklad

countries genres
id name id name
1 Slovakia 1 sci-fi
4 Czech Republic 2 drama

SELECT *
FROM countries CROSS JOIN genres
JOIN - Získavanie dát z viacerých tabuliek spájaním CROSS JOIN

CROSS JOIN – Príklad

countries genres
id name id name
1 Slovakia 1 sci-fi
4 Czech Republic 2 drama

SELECT *
FROM countries CROSS JOIN genres

id name id name
1 Slovakia 1 sci-fi
1 Slovakia 2 drama
4 Czech Republic 1 sci-fi
4 Czech Republic 2 drama
JOIN - Získavanie dát z viacerých tabuliek spájaním CROSS JOIN

CROSS JOIN – Poznámka

I samostatne veľký zmysel nemá


I niekedy sa hodí ako súčasť zložitejších príkazov (uvidíme neskôr)
JOIN - Získavanie dát z viacerých tabuliek spájaním CROSS JOIN

CROSS JOIN + WHERE = INNER JOIN

SELECT zoznam_výrazov
FROM názov_tabuľky_1 CROSS JOIN názov_tabuľky_2
WHERE podmienka

je to to isté ako
SELECT zoznam_výrazov
FROM názov_tabuľky_1 INNER JOIN názov_tabuľky_2
ON podmienka
JOIN - Získavanie dát z viacerých tabuliek spájaním CROSS JOIN

CROSS JOIN – Viacej tabuliek

názov_tabuľky_1
CROSS JOIN
názov_tabuľky_2,
...
názov_tabuľky_n
JOIN - Získavanie dát z viacerých tabuliek spájaním CROSS JOIN

FROM – Viacej tabuliek

V časti FROM môžeme uviesť tiež viacej tabuliek:


SELECT zoznam_stĺpcov
FROM názov_tabuľky_1,
názov_tabuľky_2,
...
názov_tabuľky_n

je to to isté ako:

SELECT zoznam_stĺpcov
FROM názov_tabuľky_1
CROSS JOIN názov_tabuľky_2,
...
názov_tabuľky_n
JOIN - Získavanie dát z viacerých tabuliek spájaním Alias tabuľky

JOINovanie tabuľky so samou sebou

Chceme dvojice všetkých filmov. Používateľ bude postupne vyberať ktorý


film z dvojice je podľa neho lepší:
SELECT *
FROM films
CROSS JOIN films

ERROR: table name "films" specified more than once


JOIN - Získavanie dát z viacerých tabuliek spájaním Alias tabuľky

Alias tabuľky

názov_tabuľky AS alias_tabuľky
JOIN - Získavanie dát z viacerých tabuliek spájaním Alias tabuľky

JOINovanie tabuľky so samou sebou – Pokračovanie

SELECT *
FROM films AS films1
CROSS JOIN films AS films2
JOIN - Získavanie dát z viacerých tabuliek spájaním Alias tabuľky

JOINovanie tabuľky so samou sebou – Pokračovanie

SELECT *
FROM films AS films1
CROSS JOIN films AS films2

Takto dostaneme:
I dvojice v tvare film1, film1
I okrem dvojice film1, film2 aj dvojicu film2, film1
JOIN - Získavanie dát z viacerých tabuliek spájaním Alias tabuľky

JOINovanie tabuľky so samou sebou – Pokračovanie

SELECT *
FROM films AS films1
CROSS JOIN films AS films2
WHERE films1.id < films2.id
JOIN - Získavanie dát z viacerých tabuliek spájaním JOINy a WHERE

JOINy a WHERE – Kam s podmienkou?

SELECT zoznam_výrazov
FROM názov_tabuľky_1 JOIN názov_tabuľky_2 ON podmienka
WHERE where_podmienka
...

JOIN teraz zastupuje INNER a OUTER joiny.


JOIN - Získavanie dát z viacerých tabuliek spájaním JOINy a WHERE

JOINy a WHERE – Kam s podmienkou?

1. vykonaj JOIN → máme jednu veľkú tabuľku


2. z tejto veľkej tabuľky vyber riadky, ktoré spĺňajú where_podmienku
3. ...
JOIN - Získavanie dát z viacerých tabuliek spájaním JOINy a WHERE

INNER JOIN podmienka vs WHERE podmienka

SELECT zoznam_výrazov
FROM názov_tabuľky_1
INNER JOIN názov_tabuľky_2 ON podmienka

1. kartézsky súčin tabuliek


2. vyberie riadky spĺňajúce podmienku
SELECT zoznam_výrazov
FROM názov_tabuľky_1
INNER JOIN názov_tabuľky_2 ON true
WHERE podmienka

1. kartézsky súčin tabuliek


2. vyberie všetky riadky (lebo ’true’ je pravdivé pre každý riadok)
3. z nich vyberie riadky spĺňajúce podmienku
JOIN - Získavanie dát z viacerých tabuliek spájaním JOINy a WHERE

OUTER JOIN podmienka vs WHERE podmienka


SELECT zoznam_výrazov
FROM názov_tabuľky_1
LEFT OUTER JOIN názov_tabuľky_2 ON podmienka

Uvažujme, že podmienka = false.


1. keďže podmienka je false, žiadne dva riadky sa nespoja,
2. vráti každý riadok tabuľky_1 raz,
3. v stĺpcoch tabuľky_2 budú NULLy.
SELECT zoznam_výrazov
FROM názov_tabuľky_1
LEFT OUTER JOIN názov_tabuľky_2 ON true
WHERE podmienka

1. keďže JOIN podmienka je true, vytvorí kartézsky súčin tabuliek,


2. kedže podmienka je false, do výsledku nevyberie žiaden riadok.
JOIN - Získavanie dát z viacerých tabuliek spájaním JOINy a WHERE

Použiť INNER alebo OUTER JOIN?

Majú byť vo výsledku všetky riadky jednej tabuľky aj keď pre ne neexistuje
riadok druhej tabuľky spĺňajúci podmienku?
I ak ÁNO, potom OUTER JOIN,
I ak NIE, potom INNER JOIN,
I príklady sme už videli
JOIN - Získavanie dát z viacerých tabuliek spájaním JOINy a WHERE

Použiť INNER alebo OUTER JOIN?

Porovnávame vo WHERE časti stĺpec pripájanej tabuľky s neNULLovou


hodnotou?
I ak ÁNO, potom INNER aj OUTER JOIN dajú ten istý výsledok
Ak by aj OUTER JOIN k nejakému riadku pripojil samé NULLy, tento
riadok potom vypadne kvôli WHERE podmienke.
JOIN - Získavanie dát z viacerých tabuliek spájaním JOINy a WHERE

Použiť INNER alebo OUTER JOIN? – Príklad

users
id name email country_id
1 fan123 fan123@gmail.com 1
2 johnny spam@spam.com 4
3 stellar my@email.ch NULL

countries
id name
1 Slovakia
4 Czech Republic

SELECT *
FROM users INNER JOIN countries
ON country_id = countries.id
WHERE countries.name = ’Slovakia’
JOIN - Získavanie dát z viacerých tabuliek spájaním JOINy a WHERE

Použiť INNER alebo OUTER JOIN? – Príklad

SELECT *
FROM users INNER JOIN countries
ON country_id = countries.id
WHERE countries.name = ’Slovakia’

id name email country_id id name


1 fan123 fan123@... 1 1 Slovakia
2 johnny spam@... 4 4 Czech Republic
JOIN - Získavanie dát z viacerých tabuliek spájaním JOINy a WHERE

Použiť INNER alebo OUTER JOIN? – Príklad

SELECT *
FROM users INNER JOIN countries
ON country_id = countries.id
WHERE countries.name = ’Slovakia’

id name email country_id id name


1 fan123 fan123@... 1 1 Slovakia
2 johnny spam@... 4 4 Czech Republic
JOIN - Získavanie dát z viacerých tabuliek spájaním JOINy a WHERE

Použiť INNER alebo OUTER JOIN? – Príklad

SELECT *
FROM users INNER JOIN countries
ON country_id = countries.id
WHERE countries.name = ’Slovakia’

id name email country_id id name


1 fan123 fan123@... 1 1 Slovakia
JOIN - Získavanie dát z viacerých tabuliek spájaním JOINy a WHERE

Použiť INNER alebo OUTER JOIN? – Príklad

SELECT *
FROM users LEFT OUTER JOIN countries
ON country_id = countries.id
WHERE countries.name = ’Slovakia’

id name email country_id id name


1 fan123 fan123@... 1 1 Slovakia
2 johnny spam@... 4 4 Czech Republic
3 stellar my@... NULL NULL NULL
JOIN - Získavanie dát z viacerých tabuliek spájaním JOINy a WHERE

Použiť INNER alebo OUTER JOIN? – Príklad

SELECT *
FROM users LEFT OUTER JOIN countries
ON country_id = countries.id
WHERE countries.name = ’Slovakia’

id name email country_id id name


1 fan123 fan123@... 1 1 Slovakia
2 johnny spam@... 4 4 Czech Republic
3 stellar my@... NULL NULL NULL
JOIN - Získavanie dát z viacerých tabuliek spájaním JOINy a WHERE

Použiť INNER alebo OUTER JOIN? – Príklad

SELECT *
FROM users LEFT OUTER JOIN countries
ON country_id = countries.id
WHERE countries.name = ’Slovakia’

id name email country_id id name


1 fan123 fan123@... 1 1 Slovakia
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

Vnáranie JOINov

Argumentom JOINu môže byť iný JOIN:

výraz_1 JOIN výraz_2 ON podmienka

I najprv sa vyhodnotia obe strany, čím zniknú dve tabuľky


I potom sa aplikuje JOIN a vznikne jedna tabuľka
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

JOIN môžeme uvavrieť do zátvoriek

(výraz_1 JOIN výraz_2 ON podmienka)


JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

Vnáranie JOINov – Príklad

films
id name year price
1 Léon: The Professional 1994 10
2 Django Unchained 2012 10

users
id name email country_id
1 fan123 fan123@gmail.com 1
2 johnny spam@spam.com 4
3 stellar my@email.ch NULL

countries ratings
id name user_id film_id rating
1 Slovakia 1 1 10
4 Czech Republic 3 2 9
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

Vnáranie JOINov – Príklad

Chceme hodnotenia filmov. Chceme mať meno človeka a názov krajiny,


pričom film nás nezaujíma.

SELECT users.name, countries.name, rating


FROM
(ratings INNER JOIN users ON ratings.user_id = users.id)
LEFT OUTER JOIN countries
ON users.country_id = countries.id
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

Vnáranie JOINov – Príklad

SELECT users.name, countries.name, rating


FROM
(ratings INNER JOIN users ON ratings.user_id = users.id)
LEFT OUTER JOIN countries
ON users.country_id = countries.id

user_id film_id rating


1 1 10
3 2 9
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

Vnáranie JOINov – Príklad

SELECT users.name, countries.name, rating


FROM
(ratings INNER JOIN users ON ratings.user_id = users.id)
LEFT OUTER JOIN countries
ON users.country_id = countries.id

user_id film_id rating name country_id


1 1 10 fan123 1
3 2 9 stellar NULL
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

Vnáranie JOINov – Príklad

SELECT users.name, countries.name, rating


FROM
(ratings INNER JOIN users ON ratings.user_id = users.id)
LEFT OUTER JOIN countries
ON users.country_id = countries.id

user_id film_id rating name country_id name


1 1 10 fan123 1 Slovakia
3 2 9 stellar NULL NULL
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

Vnáranie JOINov – Príklad

SELECT users.name, countries.name, rating


FROM
(ratings INNER JOIN users ON ratings.user_id = users.id)
LEFT OUTER JOIN countries
ON users.country_id = countries.id

name name rating


fan123 Slovakia 10
stellar NULL 9
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

To isté trocha ináč

SELECT users.name, countries.name, rating


FROM
(ratings INNER JOIN users ON ratings.user_id = users.id)
LEFT OUTER JOIN countries
ON users.country_id = countries.id

SELECT users.name, countries.name, ratings


FROM
ratings INNER JOIN
(users LEFT OUTER JOIN countries
ON users.country_id = countries.id)
ON ratings.user_id = users.id
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

Ak nepoužijeme zátvorky

v_0 JOIN v_1 ON p_1 JOIN v_2 ON p_2

je to isté ako

(v_0 JOIN v_1 ON p_1) JOIN v_2 ON p_2

Platí pre všetky JOINy


JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

JOINovanie nie je vo všeobecnosti asociatívne

(v_0 JOIN v_1 ON p_1) JOIN v_2 ON p_2

je vo všeobecnosti iné než

v_0 JOIN (v_1 JOIN v_2 ON p_2) ON p_1

Tu JOINom myslím CROSS, INNER, LEFT OUTER, RIGHT OUTER,


FULL OUTER JOIN.
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

JOINovanie nie je vo všeobecnosti asociatívne


Chceme zoznam všetkých filmov a k nemu pripojiť hodnotenia. Hodnotenie
sa má pripojiť iba ak je od človeka zo Slovenska. Ináč má byť NULL.

Nesprávny pokus:
SELECT films.name, rating
FROM (films LEFT JOIN ratings ON films.id = ratings.film_id)
INNER JOIN users ON ratings.user_id = users.id AND
country_id = 1

Správne riešenie:
SELECT films.name, rating
FROM films LEFT JOIN
(ratings INNER JOIN users ON ratings.user_id = users.id AND
country_id = 1)
ON films.id = ratings.film_id
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

JOINovanie nie je vo všeobecnosti asociatívne


Nesprávny pokus:
SELECT films.name, rating
FROM (films LEFT JOIN ratings ON films.id = ratings.film_id)
INNER JOIN users ON ratings.user_id = users.id AND
country_id = 1
films
id name year price
1 Léon: The Professional 1994 10

users
id name email country_id
2 johnny spam@spam.com 4

ratings
user_id film_id rating
2 1 10
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

JOINovanie nie je vo všeobecnosti asociatívne

Nesprávny pokus:
SELECT films.name, rating
FROM (films LEFT JOIN ratings ON films.id = ratings.film_id)
INNER JOIN users ON ratings.user_id = users.id AND
country_id = 1

id name user_id film_id rating


1 Léon: The Professional 2 1 10
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

JOINovanie nie je vo všeobecnosti asociatívne

Nesprávny pokus:
SELECT films.name, rating
FROM (films LEFT JOIN ratings ON films.id = ratings.film_id)
INNER JOIN users ON ratings.user_id = users.id AND
country_id = 1

id name user_id film_id rating country_id


1 Léon: The Professional 2 1 10 4
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

JOINovanie nie je vo všeobecnosti asociatívne

Nesprávny pokus:
SELECT films.name, rating
FROM (films LEFT JOIN ratings ON films.id = ratings.film_id)
INNER JOIN users ON ratings.user_id = users.id AND
country_id = 1

id name user_id film_id rating country_id


1 Léon: The Professional 2 1 10 4
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

JOINovanie nie je vo všeobecnosti asociatívne

Nesprávny pokus:
SELECT films.name, rating
FROM (films LEFT JOIN ratings ON films.id = ratings.film_id)
INNER JOIN users ON ratings.user_id = users.id AND
country_id = 1

id name user_id film_id rating country_id

Film vypadol, hoci sme ho chceli nechať.


JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

JOINovanie nie je vo všeobecnosti asociatívne


Správne riešenie:
SELECT films.name, rating
FROM films LEFT JOIN
(ratings INNER JOIN users ON ratings.user_id = users.id AND
country_id = 1)
ON films.id = ratings.film_id
films
id name year price
1 Léon: The Professional 1994 10
users
id name email country_id
2 johnny spam@spam.com 4
ratings
user_id film_id rating
2 1 10
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

JOINovanie nie je vo všeobecnosti asociatívne

Správne riešenie:
SELECT films.name, rating
FROM films LEFT JOIN
(ratings INNER JOIN users ON ratings.user_id = users.id AND
country_id = 1)
ON films.id = ratings.film_id

user_id film_id rating country_id


2 1 10 4
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

JOINovanie nie je vo všeobecnosti asociatívne

Správne riešenie:
SELECT films.name, rating
FROM films LEFT JOIN
(ratings INNER JOIN users ON ratings.user_id = users.id AND
country_id = 1)
ON films.id = ratings.film_id

user_id film_id rating country_id


2 1 10 4
JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

JOINovanie nie je vo všeobecnosti asociatívne

Správne riešenie:
SELECT films.name, rating
FROM films LEFT JOIN
(ratings INNER JOIN users ON ratings.user_id = users.id AND
country_id = 1)
ON films.id = ratings.film_id

user_id film_id rating country_id


JOIN - Získavanie dát z viacerých tabuliek spájaním Vnáranie JOINov

JOINovanie nie je vo všeobecnosti asociatívne

Správne riešenie:
SELECT films.name, rating
FROM films LEFT JOIN
(ratings INNER JOIN users ON ratings.user_id = users.id AND
country_id = 1)
ON films.id = ratings.film_id

id name user_id film_id rating country_id


1 Léon: The Professional NULL NULL NULL NULL
JOIN - Získavanie dát z viacerých tabuliek spájaním NATURAL JOIN

NATURAL JOIN

SELECT zoznam_stĺpcov
FROM názov_tabuľky_1
NATURAL JOIN názov_tabuľky_2
...

I joinovacia podmienka je implicitná (nepíše sa)


I porovnávajú sa všetky rovnomenné stĺpce navzájom
I funguje pre každý JOIN
JOIN - Získavanie dát z viacerých tabuliek spájaním NATURAL JOIN

NATURAL JOIN – Príklad

users
countries
id email country_id
country_id name
1 fan123@... 1
1 Slovakia
2 spam@... 4
4 Czech Republic
3 my@... NULL

SELECT users.email, countries.name


FROM users
NATURAL INNER JOIN countries
SELECT users.email, countries.name
FROM users
INNER JOIN countries
ON users.country_id = countries.country_id
JOIN - Získavanie dát z viacerých tabuliek spájaním NATURAL JOIN

NATURAL JOIN – nebezpečenstvo

I pridanie, odobratie stĺpca, zmena názvu stĺpca môže pokaziť existujúci


kód
I odporúča sa nepoužívať
JOIN a UPDATE, DELETE a INSERT

Section 12

JOIN a UPDATE, DELETE a INSERT


JOIN a UPDATE, DELETE a INSERT UPDATE

UPDATE – motivácia

films rates
id name year price year rate
1 Léon: The Professional 1994 10 1994 2
2 Django Unchained 2012 10 2012 3

Cheme aktualizovať cenu filmov na základe hodnôt, ktoré sú v tabuľke


rates.

films
id name year price
1 Léon: The Professional 1994 20
2 Django Unchained 2012 30
JOIN a UPDATE, DELETE a INSERT UPDATE

UPDATE

UPDATE názov_cieľovej_tabuľky
SET ...
FROM zoznam_názvov_pomocnych_tabuliek
[WHERE podmienka]

I cieľová tabuľka a pomocné tabuľky sa spoja CROSS JOINnom


I ponechajú sa riadky spĺňajúce podmienku
I prechádzajú sa riadky výslednej tabuľky – každý zodpovedá nejakému
riadku v cieľovej tabuľke a ten sa aktualizuje
JOIN a UPDATE, DELETE a INSERT UPDATE

UPDATE – riešenie

Cheme aktualizovať cenu filmov na základe hodnôt, ktoré sú v tabuľke


rates.

films rates
id name year price year rate
1 Léon: The Professional 1994 10 1994 2
2 Django Unchained 2012 10 2012 3

UPDATE films SET price = films.price * rates.rate


FROM rates
WHERE rates.year = films.year
JOIN a UPDATE, DELETE a INSERT UPDATE

UPDATE – riešenie

UPDATE films SET price = films.price * rates.rate


FROM rates
WHERE rates.year = films.year

films rates
id name year price year rate
1 Léon: The Professional 1994 10 1994 2
2 Django Unchained 2012 10 2012 3
JOIN a UPDATE, DELETE a INSERT UPDATE

UPDATE – riešenie

UPDATE films SET price = films.price * rates.rate


FROM rates
WHERE rates.year = films.year

id name year price year rate


1 Léon: The Professional 1994 10 1994 2
1 Léon: The Professional 1994 10 2012 3
2 Django Unchained 2012 10 1994 2
2 Django Unchained 2012 10 2012 3
JOIN a UPDATE, DELETE a INSERT UPDATE

UPDATE – riešenie

UPDATE films SET price = films.price * rates.rate


FROM rates
WHERE rates.year = films.year

id name year price year rate


1 Léon: The Professional 1994 10 1994 2
2 Django Unchained 2012 10 2012 3
JOIN a UPDATE, DELETE a INSERT UPDATE

UPDATE – riešenie

UPDATE films SET price = films.price * rates.rate


FROM rates
WHERE rates.year = films.year

films
id name year price
1 Léon: The Professional 1994 20
2 Django Unchained 2012 30
JOIN a UPDATE, DELETE a INSERT UPDATE

Čo ak vznikne viac riadkov pre jeden cieľový?

rates
films
year rate
id name year price
1994 2
1 Léon: The Professional 1994 10
1994 3
2 Django Unchained 2012 10
2012 3

UPDATE vezme iba jeden riadok a zvyšné odignoruje.

films
id name year price
1 Léon: The Professional 1994 20
2 Django Unchained 2012 30
JOIN a UPDATE, DELETE a INSERT UPDATE

V zozname tabuliek môžeme používať všetky JOINy

films rates
id name year price year rate
1 Léon: The Professional 1994 10 1994 2
2 Django Unchained 2012 10 2012 3

corrections
year correction
1994 0.9
2012 1.2

UPDATE films
SET price = films.price * rates.rate * corrections.correction
FROM rates JOIN corrections ON rates.year = corrections.year
WHERE rates.year = films.year
JOIN a UPDATE, DELETE a INSERT DELETE

DELETE

Podobne pre DELETE:

DELETE FROM názov_cieľovej_tabuľky


USING zoznam_pomocných_tabuliek
[WHERE podmienka]

I cieľová tabuľka a pomocné tabuľky sa spoja CROSS JOINnom


I ponechajú sa riadky spĺňajúce podmienku
I prechádzajú sa riadky výslednej tabuľky – každý zodpovedá nejakému
riadku v cieľovej tabuľke a ten sa zmaže
JOIN a UPDATE, DELETE a INSERT DELETE

DELETE – príklad

Cheme zmazať filmy, ktorých cena by sa aktualizovaním zväčšila viac než


dvakrát.

films rates
id name year price year rate
1 Léon: The Professional 1994 10 1994 2
2 Django Unchained 2012 10 2012 3

DELETE FROM films USING rates


WHERE rates.year = films.year AND rates.rate > 2

films
id name year price
1 Léon: The Professional 1994 10
JOIN a UPDATE, DELETE a INSERT DELETE

V zozname tabuliek môžeme používať všetky JOINy

V zozname tabuliek môžeme používať všetky JOINy


JOIN a UPDATE, DELETE a INSERT INSERT

INSERT

INSERT INTO názov_tabuľky


(názov_stĺpca_1, ..., názov_stĺpca_n)
dopyt

I namiesto VALUES môžeme uviesť dopyt (SELECT)


I do zadanej tabuľky sa vložia dáta z dopytu
I i-ty stĺpec zo SELECTu sa vloží do i-teho stĺpca zo zoznamu
JOIN a UPDATE, DELETE a INSERT INSERT

INSERT – Príklad

Koeficient už nebude podľa roku ale bude samostante pre každý film.
Nebudeme ich ale ukladať v tabuľke films ale film_rates.
INSERT INTO film_rates(film_id, rate)
SELECT films.id, rates.rate
FROM films JOIN rates ON films.year = rates.year
Množinové operácie

Section 13

Množinové operácie
Množinové operácie

Množinové operácie – Motivácia

Chceme identifikovať používateľov, ktorí majú slovníkové heslo. Chceme


zostrojiť slovník tak, aby v ňom boli:
I používateľské mená a
I názvy krajín.
Množinové operácie

Množinové operácie – Syntax

dopyt_1 MNOŽINOVÝ_OPERÁTOR dopyt_2

MNOŽINOVÝ_OPERÁTOR:
I UNION – riadky, ktoré vráti dopyt_1 alebo dopyt_2
I INTERSECT – riadky, ktoré vráti dopyt_1 a zároveň aj dopyt_2
I EXCEPT – riadky, ktoré vráti dopyt_1 ale nevráti dopyt_2
Množinové operácie

UNION – Príklad

users
country
id name country_id
id name
1 fan123 1
1 Slovakia
2 johnny 4
4 Czech Republic
3 stellar NULL
SELECT name FROM users
UNION
SELECT name FROM countries
name
fan123
johnny
stellar
Slovakia
Czech Republic
Množinové operácie

Množinové operácie – Počet a typy stĺpcov sa musia


zhodovať

SELECT id, name FROM users


UNION
SELECT name FROM countries
ERROR: each UNION query must have the same number
of columns
SELECT id FROM users
UNION
SELECT name FROM countries
ERROR: UNION types integer and character varying
cannot be matched
Množinové operácie

Množinové operácie – Názvy stĺpcov sa nemusia zhodovať

SELECT name FROM users


UNION
SELECT email FROM users

Vezme sa názov sĺpca z prvého dopytu:

name
fan123
johnny
stellar
fan123@gmail.com
spam@spam.com
my@email.ch
Množinové operácie

Množinové operácie – Vnáranie

DOPYT_1 OPERÁTOR_1 DOPYT_2

I dopyt môže byť aj zložený z množinových operátorov


Množinové operácie

Množinové operácie – Vnáranie

SELECT name FROM users


UNION
(SELECT name FROM countries
INTERSECT
SELECT email FROM users)
UNION
SELECT name FROM films
Množinové operácie

Množinové operácie – Ak nepoužijeme zátvorky

DOPYT_1 OPERÁTOR_1 DOPYT_2 OPERÁTOR_2 DOPYT_3

je to isté ako

(DOPYT_1 OPERÁTOR_1 DOPYT_2) OPERÁTOR_2 DOPYT_3


Množinové operácie

Množinové operácie – Odstaňujú duplicity

a
b
x SELECT * FROM a
x x
1 UNION
2 1
1 SELECT * FROM b
2 2
2
3 3
2
3
2
Množinové operácie

Množinové operácie – Odstaňujú duplicity

a
b
x SELECT * FROM a
x
1 INTERSECT
2 x
1 SELECT * FROM b
2 2
2
3
2
3
2
Množinové operácie

Množinové operácie – Odstaňujú duplicity

a
b
x SELECT * FROM a
x
1 EXCEPT
2 x
1 SELECT * FROM b
2 1
2
3
2
3
2
Množinové operácie

Multimnožinové operácie

UNION ALL, INTERSECT ALL, EXCEPT ALL berú do úvaju koľkokrát sa


riadok v tabuľke nachádza
Množinové operácie

Multimnožinové operácie – UNION ALL

x
1
a
b 1
x SELECT * FROM a
x 2
1 UNION ALL
2 2
1 SELECT * FROM b
2 2
2
3 2
2
3 2
2
3
3
Množinové operácie

Multimnožinové operácie – INTERSECT ALL

a
b
x SELECT * FROM a
x
1 INTERSECT ALL x
2
1 SELECT * FROM b 2
2
2 2
3
2
3
2
Množinové operácie

Multimnožinové operácie – EXCEPT ALL

a
b
x SELECT * FROM a
x x
1 EXCEPT ALL
2 1
1 SELECT * FROM b
2 1
2
3 2
2
3
2
Množinové operácie

(Multi)množinové operácie a ORDER BY, LIMIT a OFFSET

dopyt_1 OPERÁTOR dopyt_2


ORDER BY výrazy
LIMIT limit OFFSET offset

1. vyhodnotí sa dopyt_1,
2. vyhodnotí sa dopyt_2,
3. na výsledky sa aplikuje (multi)množinový operátor
4. výsledok sa usporiada
5. aplikuje sa LIMIT a OFFSET
Je to to isté ako:
(dopyt_1 OPERÁTOR dopyt_2)
ORDER BY výrazy
LIMIT limit OFFSET offset
Množinové operácie

Množinové operácie a ORDER BY – Príklad


users
countries
id name country_id
id name
1 fan123 1
1 Slovakia
2 johnny 4
4 Czech Republic
3 stellar NULL
SELECT name FROM users
UNION
SELECT name FROM countries
ORDER BY name
name
Czech Republic
fan123
johnny
Slovakia
stellar
Množinové operácie

ORDER BY, LIMIT, OFFSET pred množinovými operáciami

SELECT name FROM users ORDER BY name LIMIT 1


UNION
SELECT name FROM countries ORDER BY name LIMIT 1

ERROR: syntax error at or near "union"


Množinové operácie

ORDER BY, LIMIT, OFFSET pred množinovými operáciami

Jednotlivé dopyty musíme uzavrieť do zátvoriek

(SELECT name FROM users ORDER BY name LIMIT 1)


UNION
(SELECT name FROM countries ORDER BY name LIMIT 1)
Množinové operácie

(Multi)množinové operátory a NULL hodnoty

NULL hodnoty sa považujú za rovnaké (ale iné od neNULL hodnôt)

(SELECT 1, NULL)
UNION
(SELECT 1, NULL)
UNION
(SELECT 1, ’a’)

?column? ?column?
1 NULL
1 a

Ak by sa NULL považovali za rôzne, dostali by sme prvý riadok 2x


Množinové operácie

(Multi)množinové operátory a NULL hodnoty

NULL hodnoty sa považujú za rovnaké (ale iné od neNULL hodnôt)

(SELECT 1, NULL)
INTERSECT ALL
(SELECT 1, NULL)

?column? ?column?
1 NULL

Ak by sa NULL považovali za rôzne, dostali by sme 0 riadkov


Množinové operácie

(Multi)množinové operátory a UPDATE, DELETE, INSERT

(Multi)množinové operátory sa dajú použiť iba so SELECTom.


Integritné obmedzenia

Section 14

Integritné obmedzenia
Integritné obmedzenia

Čo to je?

I Integritné obmedzenie je podmienka, ktorá určuje, čo je konzistentný


stav databázy.
I Databázový systém nepovolí operáciu, ktorá by porušila nejaké
integritné obmedzenie
Integritné obmedzenia

Na čo to je?

I Zabránime, aby sa nekorektné vstupy od používateľa dostali do


databázy
I Nedovolíme, aby chybná aplikačná logika vložila do databázy
nesprávne hodnoty
I Radšej nech sa aplikácia ukončí a vypíše chybu, než by mala zapísať
nekorektné údaje
Integritné obmedzenia Dátový typy

Dátový typ

Na dátový typ stĺpca sa môžeme pozerať ako na integritné obmedzenie:


I v stĺpci môže byť hodnota iba z daného dátového typu
I pokus o vloženie hodnoty iného typu zlyhá
Integritné obmedzenia NOT NULL

NOT NULL

CREATE TABLE názov_tabuľky


(
...,
názov_stĺpca typ NOT NULL,
...
)

Nedovolí stĺpec nastaviť na hodnotu NULL


Integritné obmedzenia NOT NULL

NOT NULL – Príklad

CREATE TABLE films


(
id serial,
name varchar(50),
price numeric NOT NULL
)

INSERT INTO films (name, price) VALUES (’Bad film’, NULL)


ERROR: null value in column "price" violates
not-null constraint
Integritné obmedzenia CHECK

CHECK obmedzenie

CREATE TABLE názov_tabuľky


(
...,
názov_stĺpca typ [CONSTRAINT názov_obmedzenia]
CHECK (booleovský_výraz),
...
)

Pri akejkoľvek zmene riadku (insert, update) musí byť CHECK obmedzenie
splnené. Obmedzenie sa považuje za splnené, ak sa vyhodnotí na:
I TRUE, alebo
I NULL
Integritné obmedzenia CHECK

CHECK obmedzenie – Príklad

CREATE TABLE films


(
id serial,
name varchar(50),
price numeric CHECK (price >= 0)
)

INSERT INTO films (name, price) VALUES (’Bad film’, -55)


ERROR: new row for relation "films" violates check
constraint "films_price_check"
Integritné obmedzenia CHECK

CHECK obmedzenie – Príklad 2

CREATE TABLE films


(
id serial,
name varchar(50),
price numeric CHECK (price >= 0)
)

INSERT INTO films (name, price) VALUES (’Good film’, NULL)

films
id name price
1 Good film NULL
Integritné obmedzenia CHECK

CHECK obmedzenie – Prečo tie NULL hodnoty?

I aby sme mali možnosť stĺpec nevyplniť (NULL hodnota),


I a CHECK obmedzením kontrolovali iba vyplnené hodnoty

I na obmedzenie NULL máme predsa NOT NULL


Integritné obmedzenia CHECK

CHECK obmedzenie – na samostatnom riadku

CREATE TABLE názov_tabuľky


(
...,
[CONSTRAINT názov_obmedzenia] CHECK (booleovský_výraz),
...
)
Integritné obmedzenia CHECK

CHECK obmedzenie – na samostatnom riadku – Príklad

CREATE TABLE films


(
id serial,
name varchar(50),
price numeric CHECK (price >= 0),
discounted_price numeric CHECK (discounted_price >= 0),

CHECK (price > discounted_price)


)
Integritné obmedzenia UNIQUE

UNIQUE

CREATE TABLE názov_tabuľky


(
...,
názov_stĺpca typ [CONSTRAINT názov_obmedzenia] UNIQUE,
...
)

Nedovolí aby dva riadky v tabuľke mali v stĺpci tú istú hodnotu (porovnáva
sa operátorom =).
Integritné obmedzenia UNIQUE

UNIQUE – Príklad
CREATE TABLE users
(
id serial,
name varchar(50),
email varchar(50) UNIQUE
)

users
id name email
1 fan123 fan123@gmail.com

INSERT INTO users (name, email)


VALUES (’bad’, ’fan123@gmail.com’)
ERROR: duplicate key value violates unique
constraint "users_email_key"
Integritné obmedzenia UNIQUE

UNIQUE a NULLy

Keďže NULL = NULL neplatí, môžeme mať viac riadkov s NULLami v


UNIQUE stĺpci
CREATE TABLE users
(
id serial,
name varchar(50),
email varchar(50) UNIQUE
)

users
id name email
1 fan123 NULL
2 johnny NULL
Integritné obmedzenia UNIQUE

UNIQUE pre skupinu stĺpcov

CREATE TABLE názov_tabuľky


(
...,
[CONSTRAINT názov_obmedzenia]
UNIQUE (názov_stĺpca_1, ..., názov_stĺpca_n),
...
)

Nedovolí aby dva riadky v tabuľke mali v daných stĺpcoch tie isté hodnoty,
t.j. aby sa n-tice tvorené hodnotami uvedených stĺpcov rovnali (porovnáva
sa operátorom =).
Integritné obmedzenia UNIQUE

UNIQUE pre skupinu stĺpcov – Príklad

Maximálne jedno hodnotenie pre film a používateľa:


CREATE TABLE ratings
(
user_id integer,
film_id integer,
rating integer,

UNIQUE (user_id, film_id)


)
Integritné obmedzenia UNIQUE

UNIQUE pre skupinu stĺpcov – Príklad

ratings
user_id film_id rating
1 1 10
1 2 10

INSERT INTO ratings (user_id, film_id, rating)


VALUES (1, 1, 9)
ERROR: duplicate key value violates unique
constraint "ratings_user_id_film_id_key"
Integritné obmedzenia UNIQUE

UNIQUE pre skupinu stĺpcov a NULLy


I n-tica obsahujúca NULL sa nerovná žiadnej inej
I môžeme mať viac riadkov s tými istými hodnotami v UNIQUE
stĺpcoch, ak jeden z nich je NULL

CREATE TABLE ratings


(
user_id integer,
film_id integer,
rating integer,

UNIQUE (user_id, film_id)


)
ratings
user_id film_id rating
1 NULL 10
1 NULL 9
Integritné obmedzenia Kombinovanie integritných obmedzení

Integritné obmedzenia môžeme kombinovať – príklad

CREATE TABLE films


(
id integer,
name varchar(50),
price integer CONSTRAINT c1 CHECK(price >= 0)
NOT NULL
CONSTRAINT c2 UNIQUE
)
Integritné obmedzenia Primárny kľúč

Kľúče tabuľky

Kľúč tabuľky je množina stĺpcov, podľa ktorých vieme riadky tabuľky


jednoznačne identifikovať.

users
id name email country_id
1 martin martin.josh@gmail.com 1
2 martin martin124@yahoo.com 4
3 sue whatever@mydomain.com 4

I {id} je kľúč,
I {email} je kľúč,
I {id, email} je kľúč,
I {name} neidentifikuje riadky jednoznačne
Integritné obmedzenia Primárny kľúč

Primárny kľúč

I tabuľka môže mať viac kľúčov,


I má zmysel vybrať si jeden kľúč a tento používať v aplikácii na
identifikovanie riadkov,
I takýto kľúč budeme volať primárny kľúč
Integritné obmedzenia Primárny kľúč

Primárny kľúč – Integritné obmedzenie


Aj keď si povieme, že {id} je primárny kľúč tabuľky

users
id name email country_id
1 martin martin.josh@gmail.com 1
2 martin martin124@yahoo.com 4
3 sue whatever@mydomain.com 4

pridaním riadku môže {id} prestať byť kľúčom.

users
id name email country_id
1 martin martin.josh@gmail.com 1
2 martin martin124@yahoo.com 4
3 sue whatever@mydomain.com 4
3 someone my@email.com 6
Integritné obmedzenia Primárny kľúč

Primárny kľúč – Integritné obmedzenie – Syntax

CREATE TABLE názov_tabuľky


(
...,
názov_stĺpca typ [CONSTRAINT názov_obmedzenia]
PRIMARY KEY,
...
)
Integritné obmedzenia Primárny kľúč

Primárny kľúč – Integritné obmedzenie – Príklad

CREATE TABLE users


(
id INTEGER PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100),
country_id INTEGER
)
Integritné obmedzenia Primárny kľúč

Primárny kľúč – Integritné obmedzenie

I Je implementivané ako obmedzenie UNIQUE NOT NULL


I Može byť ale iba jedno

CREATE TABLE users


(
id INTEGER PRIMARY KEY,
email VARCHAR(100) PRIMARY KEY
)
ERROR: multiple primary keys for table "users"
are not allowed
Integritné obmedzenia Primárny kľúč

Zložený primárny kľúč – Integritné obmedzenie – Syntax

CREATE TABLE názov_tabuľky


(
...,
[CONSTRAINT názov_obmedzenia]
PRIMARY KEY (názov_stĺpca_1, ... , názov_stlĺpca_n),
)
Integritné obmedzenia Primárny kľúč

Zložený primárny kľúč – Integritné obmedzenie – Príklad

CREATE TABLE ratings


(
user_id integer,
film_id integer,
rating integer,

PRIMARY KEY (user_id, film_id)


)
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč
Cudzí kľúč je množina stĺpcov tabuľky, ktorou sa daná tabuľka odkazuje na
primárny kľúč inej tabuľky
countries
id name
1 Slovakia
4 Czech Republic

{id} je primárnym kľúčom tabuľky users


users
id name email country_id
1 martin martin.josh@gmail.com 1
2 martin martin124@yahoo.com 4
3 sue whatever@mydomain.com 4

{country _id} je cudzím kľúčom tabuľky user a odkazuje na primárny kľúč


{id} tabuľky country
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč – Integritné obmedzenie

Štandarne nám nič nebráni sa odkazovať na neexistujúci riadok.

countries
id name
1 Slovakia
4 Czech Republic

users
id name email country_id
1 martin martin.josh@gmail.com 1
2 martin martin124@yahoo.com 4
3 sue whatever@mydomain.com 5
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč – Integritné obmedzenie – Syntax

CREATE TABLE názov_tabuľky


(
...,
názov_stĺpca typ
[CONSTRAINT názov_obmedzenia]
REFERENCES názov_referencovanej_tabuľky
[(názov_referencovaného_stĺpca)],
...
)
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč – Integritné obmedzenie – Príklad

CREATE TABLE users


(
id INTEGER,
name VARCHAR(100),
email VARCHAR(100),
country_id INTEGER REFERENCES countries(id)
)
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč – Referencovaný stĺpec musí byť aspoň UNIQUE

CREATE TABLE countries


(
id INTEGER,
name VARCHAR(100)
)
CREATE TABLE users
(
id INTEGER,
name VARCHAR(100),
email VARCHAR(100),
country_id INTEGER REFERENCES countries(id)
)
ERROR: there is no unique constraint matching given keys
for referenced table "countries"
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč – Referencovaný stĺpec musí byť aspoň UNIQUE

CREATE TABLE countries


(
id INTEGER UNIQUE,
name VARCHAR(100)
)
CREATE TABLE users
(
id INTEGER,
name VARCHAR(100),
email VARCHAR(100),
country_id INTEGER REFERENCES countries(id)
)
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč – Integeritné obmedzenie

Ak referencovaný stĺpec je primárnym kľúčom referencovanej tabuľky,


nemusíme ho uviesť.
CREATE TABLE countries
(
id INTEGER PRIMARY KEY,
name VARCHAR(100),
)

CREATE TABLE users


(
id INTEGER,
name VARCHAR(100),
email VARCHAR(100),
country_id INTEGER REFERENCES countries
)
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč – Integritné obmedzenie

countries
id name
1 Slovakia
4 Czech Republic

Teraz po vykonaní príkazu


INSERT INTO users (user_id, name, email, country_id)
VALUES (4, ’alice’, ’alice@alice.sk’, 5)

dostaneme chybu
ERROR: insert or update on table "users" violates
foreign key constraint "users_country_id_fkey"

DETAIL: Key (country_id)=(5) is not present in table


"countries"
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč môže byť NULL

countries
id name
1 Slovakia
4 Czech Republic

Toto prejde bez problémov


INSERT INTO users (user_id, name, email, country_id)
VALUES (4, ’alice’, ’alice@alice.sk’, NULL)
Integritné obmedzenia Cudzí kľúč

Zložený cudzí kľúč – Integritné obmedzenie – Syntax

CREATE TABLE názov_tabuľky


(
...,
[CONSTRAINT názov_obmedzenia]
FOREIGN KEY (názov_stĺpca_1, ..., názov_stĺpca_n)
REFERENCES názov_referencovanej_tabuľky
[(názov_ref_stĺpca_1, ..., názov_ref_stĺpca_n)],
...
)
Integritné obmedzenia Cudzí kľúč

Zložený cudzí kľúč – Integritné obmedzenie – Príklad


Majme tabuľku so zloženým primárnym kľúčom (user_id, film_id)
ratings
user_id film_id name
1 1 10
1 2 8
A chceme vytvoriť tabuľku komentárov hodnotení:
CREATE TABLE comments
(
comment_id INTEGER PRIMARY KEY,
rating_user_id INTEGER,
rating_film_id INTEGER,
FOREIGN KEY (rating_user_id, rating_film_id)
REFERENCES ratings (user_id, film_id),
comment VARCHAR(255)
)
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč – Referencovať sa musíme na existujúce stĺpce

CREATE TABLE countries


(
name VARCHAR(100)
)
CREATE TABLE users
(
id INTEGER,
name VARCHAR(100),
email VARCHAR(100),
country_id INTEGER REFERENCES countries(id)
)
ERROR: column "id" referenced in foreign key constraint
does not exist
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč – Cyklická závislosť – Problém

employees
departments
employee_id
department_id
first_name
department_name
last_name
manager_id
department_id

I department_id REFERENCES departments(department_id)


I manager_id REFERENCES employees(employee_id)
Keďže tabuľky nemôžeme vytvoriť naraz, doterajší spôsob vytvárania
cudzích kľúčov neumožní vytvoriť jeden z cudzích kľúčov
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč – Cyklická závislosť – Riešenie

I vytvor tabuľky bez cudzích kľúčov,


I cudzie kľúče pridaj pomocou príkazu ALTER TABLE
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč – ALTER TABLE – Syntax

ALTER TABLE názov_tabuľky ADD


[CONSTRAINT názov_obmedzenia]
FOREIGN KEY (názov_stĺpca_1, ..., názov_stĺpca_n)
REFERENCES názov_referencovanej_tabuľky
[(názov_ref_stĺpca_1, ..., názov_ref_stĺpca_n)]
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč – Cyklická závislosť – Riešenie


CREATE TABLE employees
(
employee_id INTEGER PRIMARY KEY,
first_name VARCHAR(100),
last_name VARCHAR(100),
department_id INTEGER
)
CREATE TABLE departments
(
department_id INTEGER PRIMARY KEY,
department_name VARCHAR(100),
manager_id INTEGER REFERENCES employees (employee_id)
)
ALTER TABLE employees ADD
FOREIGN KEY (department_id)
REFERENCES departments (department_id)
Integritné obmedzenia Cudzí kľúč

Cudzí kľúč – Cyklická závislosť – Výnimka

Referencovaný stĺpec nemusí ešte existovať, ak je to stĺpec tabuľky, ktorú


práce vytvárame

CREATE TABLE employees


(
employee_id INTEGER PRIMARY KEY,
first_name VARCHAR(100),
last_name VARCHAR(100),
manager_id REFERENCES employees(employee_id)
)
úspešne prebehne
Integritné obmedzenia Cudzí kľúč

CREATE script

I je to postupnosť prevažne CREATE a ALTER príkazov, ktorých cieľom


je vytvoríť databázu s požadovanou štruktúrou
Integritné obmedzenia Cudzí kľúč

Referenčná integrita – Existujúce hodnoty

Stĺpec môže nadobúdať iba hodnoty, ktoré existujú v referencovanom stĺpci


referencovanej tabuľky alebo NULL

(to sme si už ukázali)


Integritné obmedzenia Cudzí kľúč

Referenčná integrita - Manazanie tabuľky

Nemôžeme zmazať tabuľku, ak na ňu odkazuje cudzí kľúč inej tabuľky


Integritné obmedzenia Cudzí kľúč

Referenčná integrita – Mazanie tabuľky


CREATE TABLE countries
(
id INTEGER PRIMARY KEY,
name VARCHAR(100)
)

CREATE TABLE users


(
id INTEGER PRIMARY KEY,
name VARCHAR(100),
country_id INTEGER REFERENCES countries (country_id)
)

DROP TABLE countries

ERROR: cannot drop table countries because other objects


depend on it
Integritné obmedzenia Cudzí kľúč

DROP TABLE CASCADE

DROP TABLE názov_tabuľky CASCADE

Zmaže tabuľku a aj všetky objekty, ktoré na ňu odkazujú:


I integritné obmedzenia typu cudzí kľúč,
I pohľady,
I ...

Tabuľka samotná, ktorá sa na ňu odkazovala, a aj jej stĺpce ostanú. Zmažú


sa len jej integritné obmedzenia.
Integritné obmedzenia Cudzí kľúč

Referenčná integrita – Mazanie riadkov

Nemôžeme zmazať riadok, ak na neho odkazuje iný riadok


Integritné obmedzenia Cudzí kľúč

Referenčná integrita – Mazanie riadkov


Majme tabuľky
countries users
id name id name email country_id
1 Slovakia 8 martin martin.josh@ 1
4 Czech Republic 9 martin martin124@ 4
Predpokladáme, že
country_id REFERENCES countries (id)
Po spustení príkazu
DELETE FROM countries WHERE id = 1
dostaneme chybu
ERROR: update or delete on table "countries" violates
foreign key constraint "users_countries_id_fkey"
on table "users"
DETAIL: Key (id)=(1) is still referenced from table "users"
Integritné obmedzenia Cudzí kľúč

ON DELETE

Pri vytváraní cudzieho kľúča môžeme stanoviť, čo sa má diať v prípade, že


referencovaný riadok zmažeme.
... REFERENCES názov_referencovanej_tabuľky
[(názov_ref_stĺpca_1, ..., názov_ref_stĺpca_n)]
ON DELETE názov_akcie

názov_akcie môže byť jedno z nasledovných:


I CASCADE
I SET NULL
I SET DEFAULT
Integritné obmedzenia Cudzí kľúč

ON DELETE CASCADE

Zmaže aj riadky odkazujúce na mazaný riadok


CREATE TABLE users
(
id INTEGER,
name VARCHAR(100),
email VARCHAR(100),
country_id INTEGER REFERENCES countries(id)
ON DELETE CASCADE
)
Integritné obmedzenia Cudzí kľúč

ON DELETE CASCADE

countries users
id name id name email country_id
1 Slovakia 8 martin martin.josh@ 1
4 Czech Republic 9 martin martin124@ 4

DELETE FROM countries WHERE id = 1


countries users
id name id name email country_id
4 Czech Republic 9 martin martin124@ 4
Integritné obmedzenia Cudzí kľúč

ON DELETE SET NULL

I Cudzí kľúč v odkazujúcich sa riadkoch nastaví na NULL


I Ak má cudzí kľúč obmedzenie NOT NULL, dostaneme chybu

CREATE TABLE users


(
id INTEGER,
name VARCHAR(100),
email VARCHAR(100),
country_id INTEGER REFERENCES countries(id)
ON DELETE SET NULL
)
Integritné obmedzenia Cudzí kľúč

ON DELETE SET NULL

countries users
id name id name email country_id
1 Slovakia 8 martin martin.josh@ 1
4 Czech Republic 9 martin martin124@ 4

DELETE FROM countries WHERE id = 1


users
countries
id name email country_id
id name
8 martin martin.josh@ NULL
4 Czech Republic
9 martin martin124@ 4
Integritné obmedzenia Cudzí kľúč

ON DELETE SET DEFAULT

I cudzí kľúč v odkazujúcich riadkoch nastaví na DEFAULT hodnotu


I Ak ale DEFAULT hodnota v referencovanej tabuľke neexistuje,
dostaneme chybu

CREATE TABLE users


(
id INTEGER,
name VARCHAR(100),
email VARCHAR(100),
country_id INTEGER DEFAULT 4
REFERENCES countries(id)
ON DELETE SET DEFAULT
)
Integritné obmedzenia Cudzí kľúč

ON DELETE SET DEFAULT

countries users
id name id name email country_id
1 Slovakia 8 martin martin.josh@ 1
4 Czech Republic 9 martin martin124@ 4

DELETE FROM countries WHERE id = 1


users
countries
id name email country_id
id name
8 martin martin.josh@ 4
4 Czech Republic
9 martin martin124@ 4
Integritné obmedzenia Cudzí kľúč

ON UPDATE

I Umožňuje povedať, čo sa má stať ak referencovanú hodnotu zmeníme


na inú
... REFERENCES názov_referencovanej_tabuľky
[(názov_ref_stĺpca_1, ..., názov_ref_stĺpca_n)]
ON UPDATE názov_akcie

názov_akcie môže byť jedno z nasledovných:


I CASCADE
I SET NULL
I SET DEFAULT
Integritné obmedzenia Cudzí kľúč

ON UPDATE CASCADE

Zmení cudzie kľúče v referencujúcich sa riadkoch


CREATE TABLE users
(
id INTEGER,
name VARCHAR(100),
email VARCHAR(100),
country_id INTEGER REFERENCES countries(id)
ON UPDATE CASCADE
)
Integritné obmedzenia Cudzí kľúč

ON UPDATE CASCADE

countries users
id name id name email country_id
1 Slovakia 8 martin martin.josh@ 1
4 Czech Republic 9 martin martin124@ 4

UPDATE countries SET id = 50 WHERE id = 1


countries users
id name id name email country_id
50 Slovakia 8 martin martin.josh@ 50
4 Czech Republic 9 martin martin124@ 4
Integritné obmedzenia Cudzí kľúč

ON UPDATE SET NULL

I Cudzí kľúč v odkazujúcich sa riadkoch nastaví na NULL


I Ak má cudzí kľúč obmedzenie NOT NULL, dostaneme chybu

CREATE TABLE users


(
id INTEGER,
name VARCHAR(100),
email VARCHAR(100),
country_id INTEGER REFERENCES countries(id)
ON UPDATE SET NULL
)
Integritné obmedzenia Cudzí kľúč

ON UPDATE SET NULL

countries users
id name id name email country_id
1 Slovakia 8 martin martin.josh@ 1
4 Czech Republic 9 martin martin124@ 4

UPDATE countries SET id = 50 WHERE id = 1


countries users
id name id name email country_id
50 Slovakia 8 martin martin.josh@ NULL
4 Czech Republic 9 martin martin124@ 4
Integritné obmedzenia Cudzí kľúč

ON UPDATE SET DEFAULT

I cudzí kľúč v odkazujúcich riadkoch nastaví na DEFAULT hodnotu


I Ak ale DEFAULT hodnota v referencovanej tabuľke neexistuje,
dostaneme chybu

CREATE TABLE users


(
id INTEGER,
name VARCHAR(100),
email VARCHAR(100),
country_id INTEGER DEFAULT 4
REFERENCES countries(id)
ON UPDATE SET DEFAULT
)
Integritné obmedzenia Cudzí kľúč

ON UPDATE SET DEFAULT

countries users
id name id name email country_id
1 Slovakia 8 martin martin.josh@ 1
4 Czech Republic 9 martin martin124@ 4

UPDATE countries SET id = 50 WHERE id = 1


countries users
id name id name email country_id
50 Slovakia 8 martin martin.josh@ 4
4 Czech Republic 9 martin martin124@ 4
UPSERT

Section 15

UPSERT
UPSERT

UPSERT – motivácia

Chceme uchovávať nastavenia vo formáte kľúč-hodnota.

settings
key value
timeout 30
email admin@domain.org

Chceme vložiť riadok pre kľúč timeout, no keď riadok pre tento kľúč už
existuje, chceme ho aktualizovať.
UPSERT

INSERT ON CONFLICT DO UPDATE

INSERT INTO ...


ON CONFLICT (c_názov_stĺpca_1, ..., c_názov_stĺpca_n)
DO UPDATE SET
názov_stĺpca_1 = výraz_1,
...
názov_stĺpca_m = výraz_m

I pokúsi sa o vloženie riadkov


I ak vloženie neprebehne kvôli porušeniu UNIQUE obmedzenia na
daných stĺpcoch, vykoná sa UPDATE na konfliktných riadkoch,
I riadky, na ktorých konflikt nebol sú nezmenené
UPSERT

UPSERT – riešenie

settings
key value
timeout 30
email admin@domain.org

Predpokladajme, že stĺpec key je UNIQUE.


INSERT INTO settings (key, value)
VALUES (’timeout’, ’60’)
ON CONFLICT (key) DO UPDATE
SET value = ’60’
settings
key value
timeout 60
email admin@domain.org
UPSERT

Pseudotabuľka EXCLUDED

Na neakceptovaný riadok sa môžeme odkázať pomocou pseudotabuľky


EXCLUDED

INSERT INTO settings (key, value)


VALUES (’timeout’, ’60’)
ON CONFLICT (key) DO UPDATE
SET value = EXCLUDED.value
UPSERT

Pseudotabuľka EXCLUDED

Vďaka pseudotabuľke EXCLUDED môžeme UPSERTovať viac riadkov


naraz

INSERT INTO settings (key, value)


VALUES (’timeout’, ’60’),
(’email’, ’admin@newdomain.org’)
ON CONFLICT (key) DO UPDATE
SET value = EXCLUDED.value
UPSERT

Pseudotabuľka EXCLUDED

settings
key value
timeout 30
email admin@domain.org

INSERT INTO settings (key, value)


VALUES (’timeout’, ’60’),
(’email’, ’admin@newdomain.org’)
ON CONFLICT (key) DO UPDATE
SET value = EXCLUDED.value

settings
key value
timeout 60
email admin@newdomain.org
UPSERT

DO UPDATE – WHERE podmienka

Pomocou WHERE podmineky môžeme ďalej obmedziť, ktoré riadky


povolíme aktualizovať

INSERT INTO settings (key, value)


VALUES (’timeout’, ’60’),
(’email’, ’admin@newdomain.org’)
ON CONFLICT (key) DO UPDATE
SET value = EXCLUDED.value
WHERE settings.read_only = FALSE
UPSERT

DO UPDATE – WHERE podmienka

settings
key value read_only
timeout 30 false
email admin@domain.org true
INSERT INTO settings (key, value)
VALUES (’timeout’, ’60’),
(’email’, ’admin@newdomain.org’)
ON CONFLICT (key) DO UPDATE
SET value = EXCLUDED.value
WHERE settings.read_only = FALSE

settings
key value read_only
timeout 60 false
email admin@domain.org true
UPSERT

INSERT ON CONFLICT DO NOTHING

INSERT INTO ...


ON CONFLICT (c_názov_stĺpca_1, ..., c_názov_stĺpca_n)
DO NOTHING

I pokúsi sa o vloženie riadkov


I ak vloženie neprebehne kvôli porušeniu UNIQUE obmedzenia na
daných stĺpcoch, nič sa nedeje a pokračujeme pokusom o vloženie
nasledovného riadku
I čiže konfliktné riadky sa nevložia a príkaz skončí úspechom
Podmienené výrazy

Section 16

Podmienené výrazy
Podmienené výrazy

Podmienené výrazy

Výrazy, ktorých hodnota závisí od podmienky


Podmienené výrazy

CASE – Variant testujúci podmienky

CASE WHEN podmienka_1 THEN výsledok_1


[WHEN podmienka_2 THEN výsledok_2]
...
[WHEN podmienka_n THEN výsledok_n]
[ELSE výsledok_else]
END
Hodnotou celého výrazu je:
I výraz výsledok_i prvej vetvy i, ktorej podmienka_i sa vyhodnotí na
TRUE
I ináč je výsledkom výraz výsledok_else
Podmienené výrazy

CASE – Príklad

SELECT films.id,
CASE WHEN year < 1960 THEN ’archaic’
WHEN year BETWEEN 1960 AND 2000 THEN ’old’
ELSE ’recent’
END AS comment
FROM films
Podmienené výrazy

CASE – Variant porovnávajúci výraz

CASE výraz_0
WHEN výraz_1 THEN výsledok_1
[WHEN výraz_2 THEN výsledok_2]
...
[WHEN výraz_n THEN výsledok_n]
[ELSE výsledok_else]
END
Hodnotou celého výrazu je:
I výraz výsledok_i prvej vetvy i, pre ktorú sa porovnanie
výraz_i = výraz_0 vyhodnotí na TRUE
I ináč je výsledkom výraz výsledok_else
Teda ak výraz is NULL, výsledkom je výraz výsledok_else
Podmienené výrazy

CASE – Príklad

Cenu 0 nahradíme textom ’free’.

SELECT name,
CASE price
WHEN 0 THEN ’free’
ELSE price::VARCHAR
END
FROM films

Keďže takto zmiešame čísla a text dokopy, musíme ostatné čísla


konvertovať na text.
Podmienené výrazy

Pretypovanie

hodnota::typ

CAST (hodnota AS typ)


Podmienené výrazy

COALESCE

COALESCE(hodnota_1, [, ..., hodnota_n])

I vráti prvú neNULLovú hodnotu


I ak sú všetky honoty NULL, potom vráti NULL
Podmienené výrazy

COALESCE – Príklad

SELECT user_name,
COALESCE(countries.name, ’No country’) as country_name
FROM users
LEFT JOIN countries ON users.country_id = countries.id
Podmienené výrazy

NULLIF

NULLIF(hodnota_1, hodnota_2)

I ak sa hodnoty rovnajú, vráti NULL


I ináč vráti hodnota_1
Podmienené výrazy

NULLIF – Príklad

SELECT user_name,
NULLIF(countries.name, ’No country’) as country_name
FROM ...
Agregovanie dát

Section 17

Agregovanie dát
Agregovanie dát Agregačné funkcie

Agregačné funkcie – Motivácia

ratings
user_id film_id rating
1 1 10
1 6 2
1 7 8
2 2 9
2 12 4

Chceme zistiť koľko filmov ohodnotil používateľ s id 1.

count
3
Agregovanie dát Agregačné funkcie

Agregačné funkcie

Redukujú celú tabuľku na jeden riadok


count(*)
I vráti počet riadkov

count(výraz)
I vráti počet riadkov, pre ktoré sa výraz vyhodnotí na neNULLovú
hodnotu
Agregovanie dát Agregačné funkcie

Agregačné funkcie

sum(výraz)
I vyhodnotí výraz pre každý riadok a získané hodnoty sčíta

avg(výraz)
I vyhodnotí výraz pre každý riadok a zo získaných hodnôt spraví
aritmentický priemer

max(výraz)
I vyhodnotí výraz pre každý riadok a zo získaných hodnôt vezme
maximum

min(výraz)
I vyhodnotí výraz pre každý riadok a zo získaných hodnôt vezme
minimum
Agregovanie dát Agregačné funkcie

Agregačné funkcie

bool_and(výraz)
I vyhodnotí výraz pre každý riadok
I vráti true ak všetky hodnoty sú true, ináč false
I nikdy nevráti NULL

bool_or(výraz)
I vyhodnotí výraz pre každý riadok
I vráti true ak aspoň jedna hodnota je true, ináč false
I nikdy nevráti NULL
Agregovanie dát Agregačné funkcie

Agregačné funkcie – Poradie vykonávania

1. vykonajú sa JOINy
2. vyberú sa riadky spĺňajúce WHERE podmienku
3. zatiaľ máme vo všeobecnosti tabuľku s veľa riadkami
4. aplikujú sa agregačné funkcie, čím dostaneme jeden riadok
5. idú ďalšie fázy (rekapitulácia bude neskôr)
Agregovanie dát Agregačné funkcie

Agregačné funkcie – Príklad

ratings
user_id film_id rating
1 1 10
1 6 2
1 7 8
2 2 9
2 12 4

Chceme zistiť koľko filmov ohodnotil používateľ s id 1.


SELECT count(*)
FROM ratings
WHERE user_id = 1

count
3
Agregovanie dát Agregačné funkcie

Agregačné funkcie – Príklad 2

ratings
user_id film_id rating
1 1 10
1 6 2
1 7 8
2 2 9
2 12 4

SELECT avg(rating), count(*)


FROM ratings
WHERE user_id = 1

avg count
6.667 3
Agregovanie dát Agregačné funkcie

Ak použijeme agregačnú funkciu, všetky SELECT výrazy


musia byť agregačné

SELECT user_id, count(*)


FROM ratings

ratings
user_id film_id rating
1 1 10
1 6 2
1 7 8
2 2 9
2 12 4
Agregovanie dát Agregačné funkcie

Ak použijeme agregačnú funkciu, všetky SELECT výrazy


musia byť agregačné

SELECT user_id, count(*)


FROM ratings

user_id count
12 5

Stĺpec user_id je typu číslo, nie pole čísel. Nevieme, ktorú z hodnôt si
vybrať.
Agregovanie dát Agregačné funkcie

Agregačné funkcie a NULLy

I count(*) započítava všetky riadky (aj s NULL hodnotami),


I ostatné uvedené funkcie ignorujú NULLy
Agregovanie dát Agregačné funkcie

Agregačné funkcie a NULLy – Príklad

users
id name country_id
1 fan123 1
2 johnny 4
3 stellar NULL

SELECT count(*), count(country_id)


FROM users

count count
3 2
Agregovanie dát Agregačné funkcie

Agregačné funkcie a žiadne riadky

Čo ak po aplikovaní WHERE podmienky neostane žiaden riadok?


I count – vráti 0,
I ostatné uvedené funkcie – vrátia NULL
Agregovanie dát Agregačné funkcie

Agregačné funkcie a duplicitné hodnoty

I agregačná_funkcia(výraz) – berie do úvahy duplicity


I agregačná_funkcia(ALL výraz) – berie do úvahy duplicity
I agregačná_funkcia(DISTINCT výraz) – duplicity ignoruje
Agregovanie dát Agregačné funkcie

Agregačné funkcie – Príklad 3

ratings
user_id film_id rating
1 1 10
1 6 2
2 1 9

Chceme vypočítať počet hodnotení v priemere na jeden film.

SELECT count(film_id), count(DISTINCT film_id),


count(film_id)::numeric/count(DISTINCT film_id)
AS ratings_per_film
FROM ratings

count count ratings_per_film


3 2 1.5
Agregovanie dát Agregačné funkcie

Agregovanie iba niektorých riadkov

Ak všetky agregované hodnoty majú byť z rovnakých riadkov, môžeme


použiť WHERE podmienku na výber riadkov.

Počet hodnotení > 5 a priemerné hodnotenie z hodnotení > 5

SELECT count(*), avg(rating)


FROM ratings
WHERE rating > 5
Agregovanie dát Agregačné funkcie

Agregovanie iba niektorých riadkov

Ak agregované hodnoty majú byť nad rôznymi riadkami, musíme použiť


FILTER
Počet hodnotení > 5 a priemerné hodnotenie z hodnotení <= 5
Agregovanie dát Agregačné funkcie

FILTER

názov_agregačnej_funkcie(parametre)
FILTER (WHERE podmienka)

I do aplikovania agregačnej funkcie sa dostanú len riadky, pre ktoré sa


podmienka vyhodnotí na TRUE
I podmienka môže referencovať aj iné stĺpce než tie, čo sú parametrami
agregačnej funkcie
Agregovanie dát Agregačné funkcie

Agregovanie iba niektorých riadkov

Počet hodnotení > 5 a priemerné hodnotenie <= 5

SELECT count(*) FILTER (WHERE rating > 5),


avg(rating) FILTER (WHERE rating <= 5)
FROM ratings
Agregovanie dát Agregačné funkcie

Agregovanie iba niektorých riadkov – Podmienené výrazy

SELECT count(CASE
WHEN rating > 5 THEN 1
ELSE NULL
END),
avg(CASE
WHEN rating <= 5 THEN rating
ELSE NULL
END)
FROM ratings
Agregovanie dát GROUP BY

GROUP BY

Ak nechcem agregovať celú tabuľku ale po skupinách


SELECT zoznam_select_výrazov
FROM názov_tabuľky
WHERE podmienka
GROUP BY goup_by_výraz_1, ..., group_by_výraz_n
Agregovanie dát GROUP BY

GROUP BY

SELECT zoznam_select_výrazov
FROM názov_tabuľky
WHERE podmienka
GROUP BY goup_by_výraz_1, ..., group_by_výraz_n

Ako to funguje:
I vezme zadanú tabuľku
I aplikuje WHERE podmienku
I riadky rozdelí do skupín podľa výrazov group_by_výraz_1, ...,
group_by_výraz_n
I na každú skupinu sa aplikujú agregačné funkcie
I každá skupina v pôvodnej tabuľke sa stane riadkom v novej tabuľke
Agregovanie dát GROUP BY

GROUP BY – Príklad

SELECT user_id, count(*)


FROM ratings
GROUP BY user_id

ratings
user_id film_id rating
1 1 10
1 6 2
1 7 8
2 2 9
2 12 4
Agregovanie dát GROUP BY

GROUP BY – Príklad

SELECT user_id, count(*)


FROM ratings
GROUP BY user_id

user_id film_id rating


1 1 10
1 6 2
1 7 8
2 2 9
2 12 4
Agregovanie dát GROUP BY

GROUP BY – Príklad

SELECT user_id, count(*)


FROM ratings
GROUP BY user_id

user_id count
1 3
2 2
Agregovanie dát GROUP BY

GROUP BY – Príklad 2

Koľko používateľov hodnotilo daným hodnotením daný film

SELECT film_id, rating, count(*)


FROM ratings
GROUP BY film_id, rating

ratings
user_id film_id rating
1 1 10
1 6 2
1 7 8
2 2 9
2 6 2
3 7 8
3 6 8
Agregovanie dát GROUP BY

GROUP BY – Príklad 2

Koľko používateľov hodnotilo daným hodnotením daný film

SELECT film_id, rating, count(*)


FROM ratings
GROUP BY film_id, rating

user_id film_id rating


1 1 10
2 2 9
1 6 2
2 6 2
3 6 8
1 7 8
3 7 8
Agregovanie dát GROUP BY

GROUP BY – Príklad 2

Koľko používateľov hodnotilo daným hodnotením daný film

SELECT film_id, rating, count(*)


FROM ratings
GROUP BY film_id, rating

film_id rating count


1 10 1
2 9 1
6 2 2
6 8 1
7 8 2
Agregovanie dát GROUP BY

GROUP BY – Výrazy povolené v SELECT časti

SELECT zoznam_select_výrazov
FROM názov_tabuľky
WHERE podmienka
GROUP BY group_by_výraz_1, ..., group_by_výraz_n

V zozname_select_výrazov môže byť iba:


I výraz uvedený v GROUP BY časti
I výraz obsahujúci agregačnú funkciu
Agregovanie dát GROUP BY

GROUP BY – Príklad 3

Počet filmov s hodnotením pod 5 a aspoň 5.

SELECT rating < 5, count(*)


FROM ratings
GROUP BY rating < 5

ratings
user_id film_id rating
1 1 10
1 6 2
1 7 8
2 2 9
2 6 2
3 7 4
3 6 8
Agregovanie dát GROUP BY

GROUP BY – Príklad 3

Počet filmov s hodnotením pod 5 a počet filmov s hodnotením aspoň 5.

SELECT rating < 5, count(*)


FROM ratings
GROUP BY rating < 5

user_id film_id rating


1 6 2
2 6 2
3 7 4
3 6 8
1 7 8
2 2 9
1 1 10
Agregovanie dát GROUP BY

GROUP BY – Príklad 3

Počet filmov s hodnotením pod 5 a počet filmov s hodnotením aspoň 5.

SELECT rating < 5, count(*)


FROM ratings
GROUP BY rating < 5

?column? count
true 3
false 4
Agregovanie dát GROUP BY

V GROUP BY časti môžeme použiť aj alias stĺpca

SELECT rating < 5 AS under, count(*)


FROM ratings
GROUP BY under

under count
true 3
false 4
Agregovanie dát GROUP BY

NULLy sú pre GROUP BY rovnaké – sú v jednej skupine

films
id name year price
3 Ubreakable 2000 8
2 Django Unchained 2012 10
4 Seven Samurai 1954 NULL
6 Bram Stocker’s Dracula 1992 NULL
1 Léon: The Professional 1994 NULL
SELECT price, count(*)
FROM films
GROUP BY price

price count
8 1
10 1
NULL 3
Agregovanie dát GROUP BY

Poradie vykonávania

1. vykonajú sa JOINy
2. vyberú sa riadky spĺňajúce WHERE podmienku
3. riadky sa rozdelia do skupín podľa GROUP BY
4. aplikujú sa agregačné funkcie, čím dostaneme jeden riadok pre každú
skupinu
5. ...
Tým pádom nemôžeme agregačné funkcie použiť vo WHERE časti
Agregovanie dát HAVING

HAVING

HAVING booleovský_výraz

I HAVING klauzula sa píše za GROUP BY a pred ORDER BY


I vyberá riadky po aplikovaní agregačnej funkcie
Agregovanie dát HAVING

HAVING – Príklad
Chceme filmy s aspoň dvomi hodnoteniami.
SELECT film_id
FROM ratings
GROUP BY film_id
HAVING count(*) >= 2

ratings
user_id film_id rating
1 1 10
1 6 2
1 7 8
2 2 9
2 6 2
3 7 8
3 6 8
Agregovanie dát HAVING

HAVING – Príklad

Chceme filmy s aspoň dvomi hodnoteniami.


SELECT film_id
FROM ratings
GROUP BY film_id
HAVING count(*) >= 2

user_id film_id rating


1 1 10
2 2 9
1 6 2
2 6 2
3 6 8
1 7 8
3 7 8
Agregovanie dát HAVING

HAVING – Príklad

Chceme filmy s aspoň dvomi hodnoteniami.


SELECT film_id
FROM ratings
GROUP BY film_id
HAVING count(*) >= 2

film_id count
1 1
2 1
6 3
7 2
Agregovanie dát HAVING

HAVING – Príklad

Chceme filmy s aspoň dvomi hodnoteniami.


SELECT film_id
FROM ratings
GROUP BY film_id
HAVING count(*) >= 2

film_id count
1 1
2 1
6 3
7 2
Agregovanie dát HAVING

HAVING – Príklad

Chceme filmy s aspoň dvomi hodnoteniami.


SELECT film_id
FROM ratings
GROUP BY film_id
HAVING count(*) >= 2

film_id count
6 3
7 2
Agregovanie dát HAVING

HAVING – Príklad

Chceme filmy s aspoň dvomi hodnoteniami.


SELECT film_id
FROM ratings
GROUP BY film_id
HAVING count(*) >= 2

film_id
6
7
Agregovanie dát Agregovanie a primárny kľúč

Agregovanie a primárny kľúč

users
id name email country_id
1 fan123 fan123@gmail.com 1
2 johnny spam@spam.com 4

ratings
user_id film_id rating
1 1 10
1 6 2
1 7 8
2 2 9
2 12 4
Agregovanie dát Agregovanie a primárny kľúč

Agregovanie a primárny kľúč

SELECT user_id, count(*)


FROM ratings
GROUP BY user_id

user_id count
1 3
2 2
Agregovanie dát Agregovanie a primárny kľúč

Agregovanie a primárny kľúč

Čo ak chceme namiesto user_id získať users.name ?


SELECT users.name, count(*)
FROM ratings
INNER JOIN users ON users.id = ratings.user_id
GROUP BY users.id

Štandardne dostaneme chybu:


ERROR: column "users.name" must appear in the GROUP BY
clause or be used in an aggregate function

Databázový systém nevie garantovať, že pre jedno users.id existuje iba


jedno users.name
Agregovanie dát Agregovanie a primárny kľúč

Agregovanie a primárny kľúč

Ak ale bude users.id primárnym kľúčom tabuľky user:


I nemôžeme mať dvoch user-ov s tým istým id (ani NULL),
I a teda pre jedno users.id existuje iba jedno users.name

Teraz môžeme users.name v SELECT časti použiť:

SELECT users.name, count(*)


FROM ratings
INNER JOIN users ON users.id = ratings.user_id
GROUP BY users.id

name count
fan123 3
johnny 2
Agregovanie dát Poradie agregovania

U niektorých agregačných funkciach záleží na poradí riadkov

string_agg(výraz, oddeľovač)

I pre každý riadok vyhodnotí výraz a všetky hodnoty spojí


oddeľovačom do jedného reťazca
Agregovanie dát Poradie agregovania

U niektorých agregačných funkciach záleží na poradí riadkov

excercise_tag
excercise_id tag
1 join
1 aggregation
2 join
2 subselect
3 subselect
3 join
Agregovanie dát Poradie agregovania

U niektorých agregačných funkciach záleží na poradí riadkov

SELECT excercise_id,
string_agg(tag, ’,’) AS excercise_type
FROM excercise_tag
GROUP BY excercise_id

excercise_id excercise_type
1 join,aggregation
2 join,subselect
3 subselect,join
Agregovanie dát Poradie agregovania

ORDER BY

názov_agregačnej_funkcie(parametre ORDER BY order_by_výraz)

I pred tým než na riadky aplikuje agregačnú funkciu riadky usporiada


podľa výrazu
Agregovanie dát Poradie agregovania

U niektorých agregačných funkciach záleží na poradí riadkov

SELECT excercise_id,
string_agg(tag, ’,’ ORDER BY tag) AS excercise_type
FROM excercise_tag
GROUP BY excercise_id

excercise_id excercise_type
1 aggregation,join
2 join, subselect
3 join, subselect
Agregovanie dát Poradie agregovania

ORDER BY

I ORDER BY funguje na všetkých štandardných agregačných funkciach


I niekedy jeho použitie ale nemá zmysel

SELECT max(value ORDER BY value)


FROM data
Agregovanie dát SELECT – Rekapitulácia

SELECT – Rekapitulácia

1. vyhodnotí sa FROM – JOINovaním vznikne jedna veľká tabuľka


2. aplikuje sa WHERE – ostanú iba riadky vyhovujúce podmienke
3. vytvoria sa skupiny podľa GROUP BY
4. aplikujú sa agregáty a každá skupina sa redukuje na jeden riadok
5. aplikuje sa HAVING – ostanú iba riadky vyhovujúce podmienke
6. výsledok sa usporiada podľa ORDER BY
7. vyhodia sa duplicity podľa DISTINCT (ON)
8. riadkom sa priradia poradové čísla
9. vyberú sa riadky s poradovými číslami podľa LIMIT a OFFSET
Viac zoskupovaní naraz

Section 18

Viac zoskupovaní naraz


Viac zoskupovaní naraz

Motivačný príklad – Superagregácia

payments
user_id date payment
1 ... 20
3 ... 5
2 ... 23
3 ... 20
2 ... 18
3 ... 20
4 ... 70
Viac zoskupovaní naraz

Motivačný príklad – Superagregácia

user_id total_payment
1 20
2 41
3 45
4 70
176

Posledný riadok sa nazýva superagregačný.


Viac zoskupovaní naraz

Ručné riešenie

SELECT user_id, sum(payment) AS total_payment


FROM payments
GROUP BY user_id

UNION ALL

SELECT NULL, sum(paymnet) AS total_payment


FROM payments
Viac zoskupovaní naraz

GROUPING SETS

... GROUP BY
GROUPING SETS (grouping_set_1, ..., grouping_set_n)

kde grouping_set_i je

(názov_stĺpca_i_1, ..., názov_stĺpca_i_m)


Viac zoskupovaní naraz

Riešenie cez GROUPING SETS

SELECT user_id, sum(payment) AS total_payment


FROM payments
GROUP BY GROUPING SETS ( (user_id), () )
I najpv sa robí agregácia GROUP BY (user_id)
I potom sa robí agregácia GROUP BY () – nad celou tabuľkou
I za stĺpce, ktoré v danej grouping set nie sú, ale sú v inej grouping set
sa dosadí NULL
I výsledky sa zjednotia
Viac zoskupovaní naraz

Riešenie cez GROUPING SETS


user_id date payment
1 ... 20
3 ... 5
2 ... 23
3 ... 20
... ... ...
SELECT user_id, sum(payment) AS total_payment
FROM payments
GROUP BY GROUPING SETS ( (user_id), () )
user_id total_payment
1 20
2 41
3 45
4 70
NULL 176
Viac zoskupovaní naraz

Ďalší príklad

user_id brand size payment


1 Banana M 20
3 Hot shirts and son L 5
2 Banana S 23
3 Hot shirts and son S 20

SELECT brand, size, sum(payment) AS total_payment


FROM payments
GROUP BY GROUPING SETS ( (brand), (size) )
brand size total_payment
Banana NULL 43
Hot shirts and son NULL 25
NULL M 20
NULL L 5
NULL S 43
Viac zoskupovaní naraz

ROLLUP

ROLLUP (s_1, s_2, ..., s_n-1, s_n)

je sémanticky to isté ako

GROUPING SETS (
(s_1, s_2, ..., s_n-1, s_n),
(s_1, s_2, ..., s_n-1),
...
(s_1, s_2),
(s_1),
()
)
Viac zoskupovaní naraz

ROLLUP

SELECT user_id, sum(payment) AS total_payment


FROM payments
GROUP BY GROUPING SETS ( (user_id), () )

SELECT user_id, sum(payment) AS total_payment


FROM payments
GROUP BY ROLLUP (user_id)
Viac zoskupovaní naraz

CUBE

CUBE (s_1, s_2, ..., s_n-1, s_n)

je sémanticky to isté ako

GROUPING SETS (
...
každá podmnožina (s_1, s_2, ..., s_n-1, s_n)
...
)
Viac zoskupovaní naraz

CUBE

CUBE (s_1, s_2, s_3)

je sémanticky to isté ako

GROUPING SETS (
(s_1, s_2, s_3),
(s_1, s_2 ),
(s_1, s_3),
( s_2, s_3),
(s_1 ),
( s_2 ),
( s_3),
( )
)
Viac zoskupovaní naraz

GROUPING SETS – násobenie, vnáranie a zátvorkovanie

http://www.postgresql.org/docs/current/static/
queries-table-expressions.html#QUERIES-GROUPING-SETS
Viac zoskupovaní naraz

Rôzne príčiny NULL hodnôt

user_id brand size payment


1 Banana M 20
3 Hot shirts and son L 5
2 Banana S 23
3 NULL S 20

SELECT brand, sum(payment) AS total_payment


FROM payments
GROUP BY GROUPING SETS ( (brand), () )

brand sum
Banana 43
Hot shirts and son 5
NULL 20
NULL 68
Viac zoskupovaní naraz

Funkcia GROUPING

GROUPING(výraz_1, ..., výraz_n)

I jednotlivé výrazy sa nevyhodnocujú


I pre každý riadok vracia bitovú masku, ktorá hovorí
I či je daný riadok superagregačný pre jednotlivé výrazy
Viac zoskupovaní naraz

Funkcia GROUPING
user_id brand size payment
1 Banana M 20
3 Hot shirts and son L 5
2 Banana S 23
3 NULL S 20
SELECT brand,
sum(payment),
GROUPING(brand)
FROM payments
GROUP BY GROUPING SETS ( (brand), () )
brand sum grouping
Banana 43 0b0
Hot shirts and son 5 0b0
NULL 20 0b0
NULL 68 0b1
Viac zoskupovaní naraz

Funkcia GROUPING
SELECT brand,
sum(payment),
GROUPING(brand) AS g_b,
GROUPING(size) AS g_s,
GROUPING(brand, size) AS g_bs
FROM payments
GROUP BY GROUPING SETS ( (brand), (size), () )

brand size sum g_b g_s g_bs


Banana NULL 43 0b0 0b1 0b01
Hot shirts and son NULL 5 0b0 0b1 0b01
NULL NULL 20 0b0 0b1 0b01
NULL NULL 68 0b1 0b1 0b11
NULL l 5 0x1 0b0 0b10
NULL m 20 0b1 0b0 0b10
NULL s 43 0b1 0b0 0b10
Viac zoskupovaní naraz

Funkcia GROUPING

SELECT CASE
WHEN GROUPING(brand) = 1 THEN ’all’
ELSE brand
END AS brand,
sum(payment)
FROM payments
GROUP BY GROUPING SETS ( (brand), () )

brand sum
Banana 43
Hot shirts and son 5
NULL 20
all 68
Viac zoskupovaní naraz

Komplikácia

I ak zoskupujeme podľa idčiek


I a názvy potrebujeme dotiahnut z iných tabuliek

I riešenie vyžaduje subSELECT


I čo je mimo rozsahu tejto prednášky
Normalizácia neformálne

Section 19

Normalizácia neformálne
Normalizácia neformálne

Ako spoznať, že tabuľky sú dobre navrhnuté?

Normálne formy:
I tabuľka je v 1., 2., ... normálnej forme ak spĺňa isté vlastnosti
I každá normálna forma hovorí, že tabuľka je bez istého typu defektov
I definície sú pomerne technické

Základná myšlienka:

Tabuľka by sa nemala snažiť kombinovať príliš veľa vecí dokopy. Riešením


je veci rozdeliť do viacerých tabuliek.
Normalizácia neformálne

Stĺpce sú primitívne typy – žiadne polia, množiny, ...

users
id name email country_id
fan123@gmail.com
1 fan123 1
second@email.com
2 johnny spam@spam.com 4

Ak by sme niečo také povolili, museli by sme pridať ďalšie operátory na


prácu s množinami, čím by sa systém skomplikoval.

SELECT * FROM users WHERE email CONTAINS ’second@email.com’

POZNAMKA: Kľúčové slovo CONTAINS neexistuje, vymyslel som si ho na


ilustráciu
Normalizácia neformálne

Stĺpce sú primitívne typy – žiadne polia, množiny, ...

Riešenie: rozdeliť riadky

users
id name email country_id
1 fan123 fan123@gmail.com 1
1 fan123 second@email.com 1
2 johnny spam@spam.com 4

SELECT * FROM users WHERE email = ’second@email.com’


Normalizácia neformálne

Vznikla duplicita

je spôsobená tým, že tabuľka kombinuje veľa vecí: používateľa a jeho


emailové adresy

users
id name email country_id
1 fan123 fan123@gmail.com 1
1 fan123 second@email.com 1
2 johnny spam@spam.com 4
Normalizácia neformálne

Problém: Aktualizácia mena používateľa s id 1

I nesmieme zabudnúť na všetky riadky


I ináč máme nekonzitentné dáta.

users
id name email country_id
1 fan123 fan123@gmail.com 1
1 fan123 second@email.com 1
2 johnny spam@spam.com 4
Normalizácia neformálne

Problém: Pridanie emailu používateľovi s id 1

I najprv musíme z tabuľky zistiť hodnoty stĺpcov name, country_id


I hodnoty pri zapísaní duplikujeme

users
id name email country_id
1 fan123 fan123@gmail.com 1
1 fan123 second@email.com 1
1 fan123 third@email.com 1
2 johnny spam@spam.com 4
Normalizácia neformálne

Problém: Odstránenie emailu

users
id name email country_id
1 fan123 fan123@gmail.com 1
1 fan123 second@email.com 1
2 johnny spam@spam.com 4

I Ak má viac ako jeden email, môžeme riadok zmazať

users
id name email country_id
1 fan123 fan123@gmail.com 1
2 johnny spam@spam.com 4
Normalizácia neformálne

Problém: Odstránenie emailu

users
id name email country_id
1 fan123 fan123@gmail.com 1
2 johnny spam@spam.com 4

I Ak má iba jeden email, zmazaním riadku stratíme údaje o


používateľovi
I Jediná možnosť je zmeniť email na NULL

users
id name email country_id
1 fan123 NULL 1
2 johnny spam@spam.com 4

I Pridávanie emailu sa bude zase chovať odlišne pri pridávaní prvého a


dalších emailov.
Normalizácia neformálne

V tabuľke majú byť iba stĺpce, ktoré sa jej priamo týkajú

users
id name email country_id
1 fan123 fan123@gmail.com 1
1 fan123 second@email.com 1
2 johnny spam@spam.com 4

I {email} je kľúčom tabuľky


I tabuľka je teda o emailoch a nie o používateľoch
I stĺpce name, country_id sú jednoznačne dané idčkom, ktoré nie je
kľúčom – netýkajú sa teda emailov
Normalizácia neformálne

V tabuľke majú byť iba stĺpce, ktoré sa jej priamo týkajú

Riešenie: rozdeliť tabuľku


emails
users
user_id email
id name country_id
1 fan123@gmail.com
1 fan123 1
1 second@email.com
2 johnny 4
2 spam@spam.com

SELECT *
FROM users INNER JOIN emails ON emails.user_id = users.id
WHERE email = ’second@email.com’
Normalizácia neformálne

Do tabuľky netreba dávať nezávislé veci

contacts
user_id email telephone
1 fan123@gmail.com 22-35-566
1 second@email.com 22-35-566
2 spam@spam.com 95300-164
2 spam@spam.com 14536-337

I {email, telephone} je zloženým kľúčom


I tabuľka je teda o zložených kontaktoch
I email a telephone na sebe nijako nezávisia
I na určenie user_id postačuje jeden z dvojice: email, telephone
Normalizácia neformálne

Do tabuľky netreba dávať nezávislé veci

Riešenie: rozdeliť tabuľky

emails telephones
user_id email user_id telephone
1 fan123@gmail.com 1 22-35-566
1 second@email.com 2 95300-164
2 spam@spam.com 2 14536-337
Návrh databáz / Dátové modelovanie

Section 20

Návrh databáz / Dátové modelovanie


Návrh databáz / Dátové modelovanie Pojmy

Čo je to model?

model podľa Slovníka cudzích slov (akademický):


vyjadrenie, ktoré zachováva z hľadiska svojho cieľa podstatné črty
originálu
model podľa Oxford advanced learner’s dictionary
a simplified description, especially a mathematical one, of a system
or process, to assist calculation and predictions
Návrh databáz / Dátové modelovanie Pojmy

Čo je to modelovanie?

modelovanie podľa Slovníka cudzích slov (akademický):


reprodukcia vybratých vlastností študovaného objektu na modeli na
výskumné účely
modeling podľa Oxford advanced learner’s dictionary
the work of making a simple description of a system or a process
that can be used to explain it, etc.
Návrh databáz / Dátové modelovanie Pojmy

Doména

doména podľa Krátkeho slovníka slovenského jazyka 4:


rozhodujúca oblasť pôsobenia

I bankovníctvo,
I predaj leteniek,
I výroba liekov,
I ...
Návrh databáz / Dátové modelovanie Pojmy

Dátový model

dátový model zachytáva dáta, nie správanie


Návrh databáz / Dátové modelovanie Pojmy

Modely

Databázu by sme mohli rovno navrhovať tak, že začneme definovať


tabuľky, ich stĺpce, typy, obmedzenia, kľúče, ... čo je dosť technický
(implementačný) pohľad

Taktiež sa môžeme pozrieť, aké entity v našej doméne vystupujú, aké sú


vzťahy medzi nimi a to bez toho, aby sme sa zamýšlali, či ich budeme
ukladať do tabuliek alebo nejako ináč.
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model

Je množinový pohľad na svet:


I entity,
I atribúty,
I množiny entít,
I vzťahy medzi entitami

Je to statický pohľad na svet:


I ako veci sú,
I nie ako sa menia
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Entita

I konkrétna osoba, vec, objekt

Príklad
I Janko Hraško
I Databases (1)
I ISIC number S 123 456 789 012 X
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Doména

I množina všetkých entít, ktoré sú pre konkrétnu aplikáciu zaujímavé


I budeme ju označovať D

Príklad
D = {Janko_Hrasko, Db1, ISIC_S123456789012X, ...}
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Množiny entít

I podmnožiny domény
I množiny entít, ktoré sú pre nás (aplikáciu) zaujímavé
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Množiny entít

Students ⊆ D
I všetci študenti na FMFI,
I Students = {Janko_Hrasko, ...}

Courses ⊆ D
I všetky predmety vyučované na FMFI
I Courses = {Db1, ..}

ISICs ⊆ D
I všetky ISICy študentov FMFI
I ISICs = {ISIC _S123456789012X , ...}
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Atribúty Entity

I každá entita má atribúty


I atribút má typ
I atribút ako čiastočná funkcia
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Atribúty Entity

name
I name : D → Strings
I name(JankoHasko) = ’Janko’
I name(ISIC_S123456789012X) nie je definované

birth date
I birth_date : D → Dates
I birth_date(JankoHasko) = 1-1-1990
I birth_date(ISIC_S123456789012X) nie je definované
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Vzťahy medzi entitami

I entity sú vo vzťahoch
I vzťah ako relácia
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Vzťahy medzi entitami

owns (Students – ISICs)


I študent vlastní ISIC
I owns ⊆ Students × ISICs
I Students × ISICs považujeme za typ vzťahu
I owns = {(JankoHrasko, ISIC _S123456789012X ), ....}

is enrolled in (Students – Courses)


I študent ma zapísaný predmet
I is_entrolled_in ⊆ Students × Courses
I is_entrolled_in = {(JankoHrasko, Db1), ....}
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Kardinalita binárnych relácií

A:B

I A – maximálne koľko entít z prvej množiny prislúcha jednej entite z


druhej množiny
I B – maximálne koľko entít z druhej množiny prislúcha jednej entite z
prvej množiny
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Kardinalita binárnych relácií

1:1
I jedna entina v prvej množine je vo vzťahu s maximálne jednou entitou
z druhej množiny
I a opačne

owns (Students – ISICs)


I jeden študent vlastní jeden ISIC a
I jeden ISIC je vlastnený jedným študentom
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Kardinalita binárnych relácií

1:N
I jedna entina v prvej množine je vo vzťahu s ľubovoľne veľa entitami z
druhej množiny,
I no jedna entita z druhej množiny je vo vzťahu maximálne s jednou
entitou z prvej množiny

works on (Students – Theses)


I študent pracuje na viacerých zaverečných prácach (bakalárka,
diplomovka, dizertačka),
I no každú prácu vytvára iba jeden študent
I ak by aj viacerí študenti mali tú istú tému, práce sú to ale rozdielné
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Kardinalita binárnych relácií

N:1
I to isté ako 1:N, len obrátene

created by (Theses – Students)


I jednú prácu vytvára iba jeden študent,
I no jeden človek môže vytvárať viac prác
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Kardinalita binárnych relácií

M:N
I jedna entina v prvej množine je vo vzťahu s ľubovoľne veľa entitami z
druhej množiny
I a opačne

is enrolled in (Students – Courses)


I jeden študent má zapísaných viacero predmetov,
I jeden predmet má zapísaný viacero študentov
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Atribúty vzťahov

I vzťahy môžu mať tiež atribúty


I atribút vzťahu ako funkcia

year
I rok, v ktorom má zapísaný predmet
I year : is_enrolled_in → Integers
I year ((JankoHrasko, Db1)) = 2015

final grade
I výsledná známka
I final_grade : is_enrolled_in → Grades
I final_grade((JankoHrasko, Db1)) = A
Návrh databáz / Dátové modelovanie Entitno-relačný model

Entitno-relačný model – Štruktúra vs Dáta

Entitno-relačný model môžeme rozdeliť na:

Štruktúru
I názvy množín entít
I názvy a typy atribútov
I názvy, typy a kardinalita vzťahov

Dáta
I obsah množín entít
I hodnoty atribútov
I obsah vzťahov

Pri navrhovaní sa sústredime na štruktúru.


Návrh databáz / Dátové modelovanie Štruktúra entitno-relačného modelu UML diagramom

Ako zachytiť štruktúru entitno-relačného modelu?

I slovne – vcelku neprehľadné


I matematicky
I nejakým diagramom
Návrh databáz / Dátové modelovanie Štruktúra entitno-relačného modelu UML diagramom

Diagramy pre štruktúru entitno-relačného modelu

I entitno-relačný diagram – to len aby ste vedeli, že taký pojem existuje


I UML diagram tried (class diagram) – cesta, ktorou pôjdeme my
Návrh databáz / Dátové modelovanie Štruktúra entitno-relačného modelu UML diagramom

UML class diagram – Množina entít

krabička s položkami

názov množiny entít


názov atribútu 1 : typ
názov atribútu 2 : typ

predpokladáme že entity z danej množiny majú spoločnú sadu atribútov


Návrh databáz / Dátové modelovanie Štruktúra entitno-relačného modelu UML diagramom

UML class diagram – Množina entít

students
courses
name
name
surname
recommended semester
birth date

theses
isics
name
number
goal
valid until
Návrh databáz / Dátové modelovanie Štruktúra entitno-relačného modelu UML diagramom

UML class diagram – Vzťah

čiara spájajúca krabičky

názov množiny entít 1 názov množiny entít 2


názov vzťahu
názov atribútu 1 názov atribútu 1
názov atribútu 2 názov atribútu 2
Návrh databáz / Dátové modelovanie Štruktúra entitno-relačného modelu UML diagramom

UML class diagram – Vzťah

students
courses
is enrolled in
name
name
surname
recommended semester
birth date

works on
owns

theses
isics
name
number
goal
valid until
Návrh databáz / Dátové modelovanie Štruktúra entitno-relačného modelu UML diagramom

UML class diagram – Kardinalita vzťahu

"číslo" pri čiare – počet entít z danej množiny priradených jednej entite z
druhej množiny

názov množiny entít 1 názov množiny entít 2


názov vzťahu
názov atribútu 1 A B názov atribútu 1
názov atribútu 2 názov atribútu 2

I 1 – maximálne jedna entita


I * – ľubovoľne veľa entít
Návrh databáz / Dátové modelovanie Štruktúra entitno-relačného modelu UML diagramom

UML class diagram – Kardinalita vzťahu

students
courses
is enrolled in
name
name
surname * *
recommended semester
birth date
1
1 works on
owns
1
* theses
isics
name
number
goal
valid until
Návrh databáz / Dátové modelovanie Štruktúra entitno-relačného modelu UML diagramom

UML class diagram – Atribúty vzťahu

názov vzťahu
názov atribútu 1
názov atribútu 2

názov množiny entít 1 názov množiny entít 2


názov vzťahu
názov atribútu 1 A B názov atribútu 1
názov atribútu 2 názov atribútu 2
Návrh databáz / Dátové modelovanie Štruktúra entitno-relačného modelu UML diagramom

UML class diagram – Atribúty vzťahu

is enrolled in
year
final grade
students
courses
is enrolled in
name
name
surname * *
recommended semester
birth date
1 works on
1 owns
1
* theses
isics
name
number
goal
valid until
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformovanie entitno-relačného modelu na relačný model

Výhodou entitno-relačného modelu je, že:


I nám pekne zachytáva vzťahy medzi entitami, a
I dá sa automatizovane transformovať na relačný model
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Množiny entít → tabuľky

I množina entít → tabuľka


I atribút → stĺpec
I v každej tabuľke vytvor primárny kľúč id
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Množiny entít → tabuľky

students
students
id
name
name
surname
surname
birth date
birth_date
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Vzťah 1:N

Do tabuľky na strane "N" pridaj cudzí kľúč odkazujúci sa na primárny kľúč


tabuľky na strane "1"
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Vzťah 1:N

students
theses
works on
name
1 name
surname *
goal
birth date
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Vzťah 1:N

students theses
id id
name name
surname goal
birth_date student_id
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Vzťah N:1

Analogicky ako 1:N


Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Vzťah 1:1

I vzťah 1:1 je špeciálnym prípadom vzťahov 1:N a N:1

I cudzí kľúč pridáme buď do jednej alebo do druhej tabuľky


I na cudzí kľúč pridaj UNIQUE obmedzenie
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Vzťah 1:1

students
isics
owns
name
1 1 number
surname
valid until
birth date
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Vzťah 1:1

students isics
id id
name number
surname valid_until
birth_date student_id
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Vzťah 1:1

students isics
id id
name number
surname valid_until
birth_date student_id

Tá istá transformácia ako pri 1:N


I čiže nám vznikol vzťah 1:N
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Vzťah 1:1

students isics
id id
name number
surname valid_until
birth_date student_id

Tá istá transformácia ako pri 1:N


I čiže nám vznikol vzťah 1:N

Aby sme získali 1:1 musíme pridať


I UNIQUE obmedzenie na stĺpec student_id
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Vzťah M:N

I pridaj väzobnú tabuľku


I do tejto väzobnej tabuľky pridaj dva cudzie kľúče:
I prvý sa bude odkazovať na primárny kľúč prvej tabuľky
I druhý sa bude odkazovať na primárny kľúč druhej tabuľky
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Vzťah M:N

students
courses
is enrolled in
name
name
surname * *
recommended semester
birth date
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Vzťah M:N

students
courses
enrolled
id
id
name student_id
name
surname course_id
recommended_semester
birth_date
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Atribúty vzťahu M:N

I pridaj ich do väzobnej tabuľky


Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Atribúty vzťahu M:N

is enrolled in
year
final grade
students
courses
is enrolled in
name
name
surname * *
recommended semester
birth date
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Atribúty vzťahu M:N

students enrolled
courses
id student_id
id
name course_id
name
surname year
recommended_semester
birth_date final_grade
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Atribúty vzťahu 1:N

V prvom rade by som sa zamyslel, či sú to naozaj atribúty vzťahu a nie


naviazanej entity

I pridaj ich do tabuľky na strane "N", alebo


I ich pridaj do väzobnej tabuľky
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Transformácia – Atribúty vzťahu 1:1

Obdobne
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Roly

I rola hovorí, akú úlohu zohráva entita vo vzťahu


I píše sa ku krabičkám

teachers theses
supervisor supervises
name 1 name
*
surname goal
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Roly

I hodia sa ak máme viac vzťahov medzi tými istými množinami entít

supervisor supervises
teachers 1 * theses
name name
surname oponent opposes goal
1 *
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Roly

I pri transformácii sa hodia na pomenovanie kľúčov

theses
teachers
id
id name
name goal
surname supervisor_id
oponent_id
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

N-árne vzťahy

vzťah môže byť nielen medzi dvomi entitali ale medzi N entitami
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

N-árne vzťahy – Kosoštvorec v UML class diagrame

Majiteľ podpisuje zmluvu za firmu

firms
terms

owns *
*

*
owners
* contracts
name
* terms
surname
signs
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

N-árne vzťahy – Ako čítať kardinalitu?

Kardinalita pri contracts hovorí koľko entít z contracts je vo vzťahu


signs s jednou entitou z owners a jednou entitou firms.

firms
terms

owns *
*

*
owners
* contracts
name
* terms
surname
signs

T.j. koľko zmlúv može podpisovať jeden majiteľ pre jednu firmu.
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

N-árne vzťahy – Ďalší príklad

Nahrávacie štúdio najíma herca na konkrétny film

films
name

actors
studios *
1 name
name
surname
hires
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Vzťah sa dá vždy prepísať na väzobnú množinu entít

Pointa je tá istá ako pri transformovaní vzťahu na väzobnú tabuľku.

films
name

*
actors
studios hires * 1
1 name
name *
surname

Niekedy to má väčší, inokedy menší zmysel.


Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Kedy sa to hodí?

I ak množine vieme dať zmysluplné iné meno než sa volal vzťah, alebo
I ak jej vieme dať zmysluplné atribúty

films
name

contracts actors
studios * 1
1 duration name
name *
salary surname
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Relačný vs entitno-relačný model

Môže sa zdať, že relačný a entitno-relačný model sú vlastne to isté:


I množiny entít zodpovedajú tabuľkám,
I atribúty entít stĺpcom
Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Relačný vs entitno-relačný model

Ale neexistuje ekvivalent pre vzťahy. Tie sa transformujú na


I cudzie kľúče a
I (väzobné) tabuľky

Tabuľky sú teda implementačný jazyk pre entitno-relačný model.


Návrh databáz / Dátové modelovanie Transformovanie entitno-relačného modelu na relačný model

Navrhnite entitno relačný model dát pre kino

Kino prevádzkuje viacero kinosál. Každá kinosála má istú kapacitu. Kino


má zakúpene licencie na premietanie viacerých filmov. Má vytvorený
program premietaní filmov. Každé premietanie má určený film, dátum, čas
a kinosálu. Diváci si kupujú lístky na jednotlivé premietania. Sedenie je
voľné, t.j. lístky nie sú viazané na konkrétne sedadlo v kinosále. Pri
predávani lístkov sa kontroluje iba, či sa nenaplnila kapacita kinosály.
Chceme evidovať, ktorý divák si kúpil ktorý lístok - lístky môžu kupovať iba
prihlásení používatelia eshopu.
Návrh databáz / Dátové modelovanie – Pokračovanie

Section 21

Návrh databáz / Dátové modelovanie – Pokračovanie


Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Entitno-relačný model – Podmnožiny

Niekedy identifikujeme v našej doméne množiny entít, ktoré sú v


podmnožinovom vzťahu.
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Entitno-relačný model – Podmnožiny

I Animals – množina všetkých zvierat


I Dogs – množina všetkých psov
I Cats – množina všetkých mačiek
I Pets – množina všetkých domácich maznáčikov

I Dogs je podmnožinou Animals


I Cats je podmnožinou Animals
I Pets je podmnožinou Animals
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Entitno-relačný model – Podmnožiny

I môžu byť disjunktné, napr. Dogs a Cats,


I môžu ale mať aj prienik, napr. Dogs a Pets
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Entitno-relačný model – Podmnožiny

Podmnožiny modeluje ak
I potrebujeme vedieť povedať, že entita do danej podmnožiny
patrí/nepatrí
I ak entity z danej podmnožiny majú nejaké atribúty navyše
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Entitno-relačný model – Podmnožiny

Animals
I age
I weight

Dogs
I has docked tail (má skrátený chvost)

Cats

Pets
I name
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

UML class diagram – Podmnožiny

názov množiny entít 1


názov atribútu 1
názov atribútu 2

názov množiny entít 2


názov atribútu 1
názov atribútu 2
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

UML class diagram – Podmnožiny

animals
age
weight

dogs cats pets


has docked tail name
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Podmnožiny – Transformácia na relačný model

Uvažujeme hierarchiu s koreňom

Máme viac možností:


I každá (pod)množina na samostatnú tabuľku,
I všetko dokopy
I každá kombinácia množín na samostatnú tabuľku
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Každá (pod)množina na samostatnú tabuľku

I každá množina entít → samostatná tabuľka


I koreňová tabuľka dostane primárny kľúč id
I ostatné tabuľky dostanú primárny kľúč, ktorý bude zároveň cudzím
kľúčom do koreňovej tabuľky

Jedna entita je uložená distrubuovane vo viacerých tabuľkách.


Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Každá (pod)množina na samostatnú tabuľku

dogs
animal_id
has_docked_tail

animals
cats
id
age animal_id
weight

pets
animal_id
name
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Každá (pod)množina na samostatnú tabuľku

Výhody
I žiadna duplicita stĺpcov (stĺpce sa neopakujú)
I žiadne nepotrebné veci navyše
I entity z jednej množiny v jednej tabuľke

Nevýhody
I zložitejšia práca s dátami:
I ak chceme všetky atribúty, musíme JOINovať,
I ak chceme prvky z viacerých podmnožín, musíme použiť množinové
operácie
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Všetko dokopy

Pre celú hierarchiu vytvoríme jednú tabuľku, ktorá


I dostane primárny kľúč id
I bude mať atribúty všetkých množín,
I ak by bol konflit medzi názvami atribútov, tak ich vhodne
premenujeme,
I atribúty, ktoré nie sú v koreni musia povoľovať NULL hodnoty
I ak entita nie je z danej podmnožiny, atribúty danej podmnožiny sú
nastavené na NULL
I pre každú podmnožinu vytvor stĺpec – boolean určujúci príslušnosť do
množiny

Tabuľka bude ukladať entity zo všetkých množín.


Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Všetko dokopy

animals
id
age
weight
is_dog
has_docket_tail
is_cat
is_pet
name
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Všetko dokopy

Výhody
I žiadna duplicita stĺpcov (stĺpce sa neopakujú)
I štací pristupovať do jednej tabuľky:
I netreba JOINovať,
I množinové operácie na úrovni booleovského vyrazu nad stĺpcami is_

Nevýhody
I pri veľkom počte atribútov v podmnožinách sa veľa miesta zbytočne
minie na NULL hodnoty atribútov, ktoré pre dané entity nie sú
relevantné
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Každá kombinácia množín na samostatnú tabuľku

Pre každú prípustnú kombináciu množín vytvor samotatnú tabuľku:


I tabuľka dostane primárny kľúč id,
I bude mať atribúty všetkých množín z danej kombinácie

Tabuľka bude ukladať entity, ktoré patria práve do tých množín, pre ktoré
bola vytvorená (a do ostatných množín nepatria).
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Každá kombinácia množín na samostatnú tabuľku

animals

id
age
weight

animals_dogs animals_cats animals_pets

id id id
age age age
weight weight weight
has_docked_tail name

animals_dogs_pets animals_cats_pets

id id
age age
weight weight
has_docked_tails name
name
Návrh databáz / Dátové modelovanie – Pokračovanie Podmnožiny

Každá kombinácia množín na samostatnú tabuľku

Výhody
I priestor sa nemíňa na NULL hodnoty
I ak chceme všetky atribúty tej istej entity, nepotrebujeme JOINy –
všetky jej atribúty sú v jednej tabuľke

Nevýhody
I ten istý atribút je vo viacerých tabuľkách
I ak chceme všetky entity z jednej množiny, vo všeobecnosti musíme
zjednotiť výsledky z viacerých tabuliek, napr. pre všetky psy musíme
zjenotiť animals_dogs a animals_dogs_pets.
Návrh databáz / Dátové modelovanie – Pokračovanie Vypočítané množiny

Vypočítané množiny

Nie všetky množiny predstavujú nejakú novú informáciu, ale vieme ich
vypočítať z ostatných dát.

Také množiny nechceme transformovať na tabuľky, nakoľko by to


znamenalo duplicitu dát.
Návrh databáz / Dátové modelovanie – Pokračovanie Vypočítané množiny

Vypočítané množiny

persons
name
surname
birth date

students teachers
*
is enrolled in
* *
teaches
*
courses
name

Students a Teachers majú spoločný prienik, napr. doktorandov


Návrh databáz / Dátové modelovanie – Pokračovanie Vypočítané množiny

Vypočítané množiny

Students
množina všetkých entít z Persons, ktoré sú vo vzťahu enroled_in s
nejakou entitou z Courses

Teachers
množina všetkých entít z Persons, ktoré sú vo vzťahu teaches s nejakou
entitou z Courses
Návrh databáz / Dátové modelovanie – Pokračovanie Vypočítané množiny

Vypočítané množiny

I Oba tieto výpočty vieme vyjadriť v SQL.


I Takže pri transformácii na relačný model Students a Teachers
netransformujeme na tabuľky.
Návrh databáz / Dátové modelovanie – Pokračovanie Vypočítané množiny

Vypočítané množiny

persons
id
name
surname
birth_date
enrolled teaches
person_id person_id
course_id course_id
courses
id
name
Návrh databáz / Dátové modelovanie – Pokračovanie Vypočítané množiny

Vypočítané množiny

Vieme ich vyjadriť ako pohľady (views)


Návrh databáz / Dátové modelovanie – Pokračovanie Vypočítané množiny

Pohľad (VIEW)

I pohľad je niečo ako tabuľka – má riadky a sĺpce,


I jeho obsah ale databázový systém vypočíta na základe SQL príkazu,
ktorý mu dáme pri vytváraní pohľadu,
I riadky pohľadu nie sú uložené na disku,
I databázový systém ich zakaždým vypočíta
Návrh databáz / Dátové modelovanie – Pokračovanie Vypočítané množiny

Pohľad – Syntax

CREATE VIEW názov_pohľadu


AS dopyt
Návrh databáz / Dátové modelovanie – Pokračovanie Vypočítané množiny

Pohľad – Príklad

CREATE VIEW students


AS
SELECT DISTINCT p.*
FROM persons AS p
JOIN enrolled_in AS e ON e.person_id = p.id
Návrh databáz / Dátové modelovanie – Pokračovanie Vypočítané množiny

Pohľad

Pohľad vieme použiť podobne ako tabuľku


SELECT * FROM students
WHERE birth_date > DATE ’1993-06-07’

Za istých podmienok sa dá do pohľadu vkladať, aktualizovať, mazať. K


tomu inokedy.
Návrh databáz / Dátové modelovanie – Pokračovanie Kontextovo závislé množiny

Kontextovo závislé množiny

I niektoré množiny sa menia / sú kontextovo závislé

Students
I množina všetkých študentov závisí od kontextu,
I v tomto prípade je kontextom čas
I napr. v roku 2014 som študentom a v roku 2015 už nie som,
Návrh databáz / Dátové modelovanie – Pokračovanie Kontextovo závislé množiny

Kontextovo závislé množiny

I entitno relačný model zachytáva statický pohľad na svet


I nepodporuje explicitné zachytenie kontextu
Návrh databáz / Dátové modelovanie – Pokračovanie Kontextovo závislé množiny

Kontextovo závislé množiny

persons
enrolled in
name
surname year
birth date

students enrolled in courses


* * name

I enrolled in – vzťah je vďaka atribútu year závislý od času,


I Students
I množina je stále kontextovo nezávislá
I jediný rozumný význam: množina všetkých, minulých aj súčasných,
študentov
Návrh databáz / Dátové modelovanie – Pokračovanie Kontextovo závislé množiny

Kontextovo závislé množiny

Atribút year môžeme preniesť do pohľadu students

CREATE VIEW students


AS
SELECT DISTINCT p.*, e.year
FROM persons AS p
JOIN enrolled_in AS e ON e.person_id = p.id
Návrh databáz / Dátové modelovanie – Pokračovanie Kontextovo závislé množiny

Kontextovo závislé množiny

Potom v každom SELECTe musíme povedať rok

SELECT * FROM students


WHERE birth_date > DATE ’1993-06-07’ AND year = 2015
Návrh databáz / Dátové modelovanie – Pokračovanie Kontextovo závislé množiny

Kontextovo závislé množiny

Kontextovú množinu môžeme implementovať aj ako funkciu, ktorá berie na


vstupe kontext a vracia tabuľku.

CREATE FUNCTION students (in_year integer)


RETURNS TABLE (
id integer, name varchar,
surname varchar, birth_date date
) AS $$
SELECT DISTINCT p.*
FROM persons AS p
JOIN enrolled_in AS e ON e.person_id = p.id
WHERE e.year = in_year
$$ LANGUAGE SQL
Návrh databáz / Dátové modelovanie – Pokračovanie Kontextovo závislé množiny

Kontextovo závislé množiny

Potom vieme funkciu použiť namiesto tabuľky

SELECT *
FROM students(2015)
WHERE birth_date > DATE ’1993-06-07’
Návrh databáz / Dátové modelovanie – Pokračovanie Typy a reifikované množiny

Typ entity

Typ entity
je množina všetkých entít s danou vlastnosťou.
Návrh databáz / Dátové modelovanie – Pokračovanie Typy a reifikované množiny

Typ entity

animals
age
weight

dogs cats

množiny Cats, Dogs


predstavujú typy zvierat – entít z Animals
Návrh databáz / Dátové modelovanie – Pokračovanie Typy a reifikované množiny

Typ entity

Predstavme si, že používateľ chce vypísať všetky zvieratá, pričom typ


zvieraťa bude vyberať z nejakého dropdown-u.
Návrh databáz / Dátové modelovanie – Pokračovanie Typy a reifikované množiny

Typ entity

Ak množiny Cats a Dogs transformujeme hociktorou zo spomínaných


statégií, musíme robiť nejaký if.

if(input_type == ’cats’) {
SELECT * FROM cats;
} else if (input_typ == ’dogs’) {
SELECT * FROM dogs;
}

if(input_type == ’cats’) {
SELECT * FROM animals WHERE is_cat = TRUE;
} else if (input_typ == ’dogs’) {
SELECT * FROM animals WHERE is_dog = TRUE;
}
Návrh databáz / Dátové modelovanie – Pokračovanie Typy a reifikované množiny

Reifikovaná množina

Alternatívou je množiny Cats a Dogs reifikovať:


I každá množina sa stane entitou
I tieto entity budú tvoriť novú množinu AnimalTypes
I potom môžeme dať množinu Animals do vzťahu s množinou
AnimalTypes
Návrh databáz / Dátové modelovanie – Pokračovanie Typy a reifikované množiny

Reifikovaná množina

animals is type of animal types


age 1
* name
weight

dogs cats

Dogs a Cats
sú potom vypočítané množiny – patria do nich také entity ktoré majú
naviazaný daný typ
Návrh databáz / Dátové modelovanie – Pokračovanie Typy a reifikované množiny

Reifikovaná množina

animals
types
id
id
weight
name
type_id

Náš SELECT môžeme potom jednoducho zapísať ako:

SELECT * FROM animals WHERE type_id = :input_type


Návrh databáz / Dátové modelovanie – Pokračovanie Typy a reifikované množiny

Reifikovaná množina

reify podľa www.oxforddictionaries.com:


Zmeniť (niečo abstraktné) na konkrétnejšie, skutočnejšie
Návrh databáz / Dátové modelovanie – Pokračovanie Meta modelovanie

Chceme uchovávať rôzne produkty s rôznymi atribútmi

products
price
weight

books mouses tvs


author width resolution
title height width
format number of buttons height
number of pages type diagonal
Návrh databáz / Dátové modelovanie – Pokračovanie Meta modelovanie

Čo ak chceme za behu pridávať a odoberať typy produktov?

I pridávame, odoberáme, modifikujeme štruktúru tabuliek


I relačné databázové systémy sú postavené na predpoklade, že máme
fixné tabuľky a meníme dáta
I niektoré systémy nepodporujú pridávanie, odoberanie, modifikovanie
tabuliek v transakcii
Návrh databáz / Dátové modelovanie – Pokračovanie Meta modelovanie

Čo ak chceme zistiť typy podporovaných produktov?

I musíme zistiť aké tabuľky máme v databáze


I nie všetky tabuľky zodpovedajú typom produktov, pravdepodobne
users, orders, ...
Návrh databáz / Dátové modelovanie – Pokračovanie Meta modelovanie

Meta modelovanie

I zachytenie v modeli info o tom istom (inom) modeli


Návrh databáz / Dátové modelovanie – Pokračovanie Meta modelovanie

Meta modelovanie

types has attributes


name * * name

1
is of type
*

products has value


* *

has value
value
Návrh databáz / Dátové modelovanie – Pokračovanie Meta modelovanie

Meta modelovanie

has
attributes type_id attribute_id
types
id name 1 1
id name
1 price 1 2
1 book
2 weight 1 3
2 mouse
3 author 2 1
2 2

has_value
products
product_id attribute_id value
id type_id
1 1 10
1 1
1 2 2
3 2
1 3 Bram Stocker
Návrh databáz / Dátové modelovanie – Pokračovanie Návrhové princípy

Návrhové princípy – Vernosť

Entity, množiny, atribúty a relácie by mali verne odrážať realitu/aplikáciu.


Návrh databáz / Dátové modelovanie – Pokračovanie Návrhové princípy

Návrhové princípy – Vernosť

universities

1
1
*
*
faculties departments
Návrh databáz / Dátové modelovanie – Pokračovanie Návrhové princípy

Návrhové princípy – Vernosť

universities

1
*
faculties

1
*
departments
Návrh databáz / Dátové modelovanie – Pokračovanie Návrhové princípy

Návrhové princípy – Vyhnutie sa redundancii

Veci by sme mali mať v modeli uložené len raz a ostatné veci z nich
vypočítať.
Návrh databáz / Dátové modelovanie – Pokračovanie Návrhové princípy

Návrhové princípy – Vyhnutie sa redundancii

universities

1
1

*
*

faculties 1 * departments
Návrh databáz / Dátové modelovanie – Pokračovanie Návrhové princípy

Návrhové princípy – Vyhnutie sa redundancii

universities

faculties 1 * departments
Návrh databáz / Dátové modelovanie – Pokračovanie Návrhové princípy

Návrhové princípy – Jednoduchosť

Make everything as simple as possible, but not simpler

Albert Einstein
Návrh databáz / Dátové modelovanie – Pokračovanie Návrhové princípy

Návrhové princípy – Jednoduchosť

boards rows
1 * row number

cells
column number
symbol
Návrh databáz / Dátové modelovanie – Pokračovanie Návrhové princípy

Návrhové princípy – Jednoduchosť

cells
boards row number
1 * column number
symbol

Všetko však záleží od toho, čo potrebujeme s dátami potom robiť.


Vnorené SELECTy

Section 22

Vnorené SELECTy
Vnorené SELECTy

Vnorený SELECT

Použitie SELECTu na mieste, kde sme doteraz písali:


I hodnotu
I názov sĺpca
I názov tabuľky
I ...

Vnorený SELECT sa uzatvára do guľatých zátvoriek:

(SELECT ... )
Vnorené SELECTy Skalárne vnorené SELECTy

Skalárne vnorené SELECTy

Je to vnorený SELECT, ktorý


I vracia tabuľku rozmerov: jeden riadok × jeden stĺpec
I môže byť všade tam, kde očakávame jednu hodnotu
I ak vráti nula riadkov, považuje sa to za NULL hodnotu
Vnorené SELECTy Skalárne vnorené SELECTy

Skalárne vnorené SELECTy – Príklad

Chceme získať všetky filmy natočené v najstaršom roku.


I Nemôžeme použiť ORDER BY a LIMIT, lebo nevieme koľko ich je

SELECT *
FROM films AS f
WHERE f.year = (SELECT min(year) FROM films)
Vnorené SELECTy Skalárne vnorené SELECTy

Skalárne vnorené SELECTy – Príklad

Chceme získať všetky filmy natočené v najstaršom roku.


I Nemôžeme použiť ORDER BY a LIMIT, lebo nevieme koľko ich je

SELECT *
FROM films AS f
WHERE f.year = (SELECT min(year) FROM films)

Ak sa vnorený SELECT neodkazuje na vonkajší SELECT


I vnorený SELECT je vyhodnotený samostatne
I jeho výsledok je dosadený do vonkajšieho SELECTu
I a ten sa následne spustí
I platí aj pre iné než skalárne subquery (na ďalších slajdoch)
Vnorené SELECTy Skalárne vnorené SELECTy

Skalárne vnorené SELECTy – Príklad 2

Pre každý film chceme zistiť o koľko rokov bol natočený neskôr ako
najstarší film.

SELECT *, year - (SELECT min(year) FROM films) AS delta


FROM films AS f
Vnorené SELECTy Skalárne vnorené SELECTy

Odkazovanie sa na stĺpce vonkajšieho SELECTu – Príklad

Pre každý film chceme vedieť koľko filmov bolo vyrobených pred ním.

SELECT *, (SELECT count(*)


FROM films AS f2
WHERE f2.year < f.year) AS how_many
FROM films AS f
Vnorené SELECTy Skalárne vnorené SELECTy

Odkazovanie sa na stĺpce vonkajšieho SELECTu – Príklad

Pre každý film chceme vedieť koľko filmov bolo vyrobených pred ním.

SELECT *, (SELECT count(*)


FROM films AS f2
WHERE f2.year < f.year) AS how_many
FROM films AS f

Ak sa vnorený SELECT odkazuje na vonkajší SELECT


I pre každý riadok hlavného SELECTu sa vykoná vnorený SELECT
I pri vykonávaní vnoreného SELECTu sa použijú hodnoty aktuálneho
riadku
I platí aj pre iné než skalárne subquery (na ďalších slajdoch)
Vnorené SELECTy Skalárne vnorené SELECTy

Skalárne vnorené SELECTy – Neexistujúca hodnota

Ak skalárny vnorený SELECT vráti nula riadkov, chápe sa to ako NULL


hodnota

Pre každý film získaj jeden film, ktorý bol natočený aspoň rok po ňom.

SELECT *, (SELECT f2.name


FROM films AS f2
WHERE f2.year > f.year
ORDER BY f2.year ASC
LIMIT 1) AS next
FROM films AS f
Vnorené SELECTy Skalárne vnorené SELECTy

Skalárne vnorené SELECTy – Chyby

Ak vnorený SELECT na mieste, kde očakávame jednu hodnotu, vráti viac


riadkov (čo príklad nižšie predpokladá),

SELECT *, (SELECT f2.name


FROM films AS f2
WHERE f2.year > f.year
ORDER BY f2.year ASC) AS next
FROM films AS f

dostaneme chybu

ERROR: more than one row returned by


a subquery used as an expression
Vnorené SELECTy Skalárne vnorené SELECTy

Skalárne vnorené SELECTy – Chyby

Ak vnorený SELECT na mieste, kde očakávame jednu hodnotu, vracia viac


stĺpcov,

SELECT *, (SELECT f2.id, f2.name


FROM films AS f2
WHERE f2.year > f.year
ORDER BY f2.year ASC
LIMIT 1) AS next
FROM films AS f

dostaneme chybu

ERROR: subquery must return only one column


Vnorené SELECTy Vnorený SELECT ako zoznam hodnôt

Vnorený SELECT ako zoznam hodnôt

I operátory ako IN, NOT IN, SOME, ALL pracujú so zoznamom hodnôt
I tabuľku s jednym sĺpcom môžeme chápať ako zoznam hodnôt
I zoznam hodnôt môžme nahradiť vnoreným SELECTom, ktorý vracia
takúto tabuľku
Vnorené SELECTy Vnorený SELECT ako zoznam hodnôt

Operátor IN

hodnota IN subquery

I testuje či sa hodnota na ľavej strane nachádza v zozname, ktorý


vygereruje subquery
Vnorené SELECTy Vnorený SELECT ako zoznam hodnôt

Operátor IN – Príklad

SELECT *
FROM films
WHERE id IN (SELECT film_id FROM ratings)
Vnorené SELECTy Vnorený SELECT ako zoznam hodnôt

Operátor NOT IN

hodnota NOT IN subquery

I testuje, či sa hodnota na ľavej strane nenachádza v zozname


Vnorené SELECTy Vnorený SELECT ako zoznam hodnôt

Operátor NOT IN – Príklad

SELECT *
FROM departments
WHERE department_id NOT IN (SELECT department_id
FROM employees)
Vnorené SELECTy Vnorený SELECT ako zoznam hodnôt

Pozor na NULLy

SELECT *
FROM departments
WHERE department_id NOT IN (SELECT department_id
FROM employees)

V našej databáze sme mali zamestnanca bez oddelenia. Čiže tento


SELECT je principiálne ekvivalentný SELECTu:

SELECT *
FROM departments
WHERE department_id NOT IN (10, 100, NULL, 50)
Vnorené SELECTy Vnorený SELECT ako zoznam hodnôt

Pozor na NULLy

department_id NOT IN (10, 100, NULL, 50)

sa vyhodnotí na:
I FALSE pre department_id 10, 100, 50
I NULL pre všetky ostatné department_id

Teda sa nevyhodnotí na TRUE pre žiadne department_id a WHERE


vyhodí z výsledku všetky oddelenia.
Vnorené SELECTy Vnorený SELECT ako zoznam hodnôt

Predčasné ukončenie

Vnorený SELECT sa prestane vykonávať v momente, keď je o výsledku


testu IN/NOT IN rozhodnuté – nemusí načítať všetky riadky.

SELECT *
FROM departments AS d
WHERE manager_id IN (SELECT manager_id
FROM employees AS e
WHERE d.id != e.department_id)
Vnorené SELECTy Vnorený SELECT ako zoznam hodnôt

Operátor ANY/SOME

hodnota operátor ANY subquery


hodnota operátor SOME subquery

I testuje či sa hodnota na ľavej strane vyhodnotí daným operátorom na


TRUE s aspoň jednou hodnotou v zozname, ktorý vygereruje subquery
Vnorené SELECTy Vnorený SELECT ako zoznam hodnôt

Operátor ANY/SOME – Príklad

Zoznam filmov, od ktorých existuje drahší film

SELECT *
FROM films AS f
WHERE price < ANY (SELECT price
FROM films AS f2
WHERE f2.id != f.id)
Vnorené SELECTy Vnorený SELECT ako zoznam hodnôt

Operátor ALL

hodnota operátor ALL subquery

I testuje či sa hodnota na ľavej strane vyhodnotí daným operátorom na


TRUE so všetkými hodnotami v zozname, ktorý vygereruje subquery
Vnorené SELECTy Vnorený SELECT ako zoznam hodnôt

Operátor ALL – Príklad

Zoznam filmov, ktoré majú nižšiu cenu ako všetky ostatné filmy

SELECT *
FROM films AS f
WHERE price < ALL (SELECT price
FROM films AS f2
WHERE f2.id != f.id)
Vnorené SELECTy EXISTS

Operátor EXISTS

EXISTS subquery

I vráti TRUE práve vtedy keď subquery vráti aspoň jeden riadok
I je jedno koľko stĺpcov subquery vracia
I vrátené hodnoty sa ignorujú – podstatné je, či vráti nejaký riadok

NOT EXISTS subquery

I negácia
Vnorené SELECTy EXISTS

Operátor EXISTS – Príklad

Získame iba také filmy, pre ktoré neexistuje starší lacnejší film

SELECT *
FROM films AS f
WHERE NOT EXISTS
(SELECT NULL
FROM films AS f2
WHERE f2.year < f.year AND f2.price < f.price)
Vnorené SELECTy EXISTS

Operátor EXISTS – Príklad 2

Pre každý film zistime, či od neho existuje starší lacnejší film

SELECT *, EXISTS (SELECT NULL


FROM films AS f2
WHERE f2.year < f.year AND f2.price < f.price) AS exists
FROM films AS f
Vnorené SELECTy EXISTS

Operátor EXISTS – Predčasné ukončenie

Vnorený SELECT sa prestane vykonávať v momente, keď je o výsledku


testu EXISTS rozhodnuté – nemusí načítať všetky riadky.
Vnorené SELECTy Vnorený SELECT namiesto názvu tabuľky

Vnorený SELECT namiesto názvu tabuľky

Napr. ak chceme agregovať po použití LIMIT

SELECT avg(tmp.price)
FROM (SELECT price
FROM films
ORDER BY year DESC
LIMIT 10) AS tmp

Vypočítana tabuľka musí mať alias


Vnorené SELECTy Vnorený SELECT namiesto názvu tabuľky

Vnorený SELECT namiesto názvu tabuľky

Čo ak sa chceme vo vnorenom dopyte (na pozícii názvu tabuľky) odkazovať


na vonkajší dopyt?
Vnorené SELECTy Vnorený SELECT namiesto názvu tabuľky

Vnorený SELECT namiesto názvu tabuľky

SELECT *
FROM departments AS d
CROSS JOIN (SELECT *
FROM employees AS e
WHERE e.department_id = d.department_id
ORDER BY salary DESC
LIMIT 3) AS top_employees
Vnorené SELECTy Vnorený SELECT namiesto názvu tabuľky

Vnorený SELECT namiesto názvu tabuľky

V PostgreSQL ≤ 9.2 to možné nie je


Vnorené SELECTy Vnorený SELECT namiesto názvu tabuľky

Vnorený SELECT namiesto názvu tabuľky

V PostgreSQL ≥ 9.3 musíme použiť LATERAL


Vnorené SELECTy Vnorený SELECT namiesto názvu tabuľky

Vnorený SELECT namiesto názvu tabuľky

SELECT *
FROM departments AS d
CROSS JOIN LATERAL (SELECT *
FROM employees AS e
WHERE e.department_id = d.department_id
ORDER BY salary DESC
LIMIT 3) AS top_employees
Vnorené SELECTy Vnorený SELECT namiesto názvu tabuľky

Kde všade sa môže vnorený SELECT nachádzať?

I na veľa miestach
I avšak nie všade, napr. nie v CHECK obmedzení
I niekedy to nie je jasné ani z PostgreSQL dokumentácie:(
I vyvíja sa to v čase, napr. UPDATE v časti SET od verzie 9.5
Konštrukcia WITH

Section 23

Konštrukcia WITH
Konštrukcia WITH

Označuje sa aj Common Table Expressions


Konštrukcia WITH WITH na sprehľadnenie zápisu SQL príkazov

Čo je to WITH?

WITH je konštrukcia, ktorá umožňuje rozbiť zložitý SQL príkaz na viac


jednoduchých
Konštrukcia WITH WITH na sprehľadnenie zápisu SQL príkazov

Motivácia – Cheme hercov, ktorí hrali v TOP 10 filmoch

I TOP filmy – podľa priemerného hodnotenia používateľmi


I hodnotenia obsahujú duplicity, cheme iba najnovšie hodnotenia

SELECT * FROM actors WHERE EXISTS


(SELECT NULL FROM plays
WHERE plays.actor_id = actors.id AND plays.film_id IN
(SELECT film_id FROM
(SELECT DISTINCT ON (user_id, film_id)
user_id, film_id, rating
FROM ratings ORDER BY user_id, film_id, time DESC
) AS tmp
GROUP BY film_id ORDER BY avg(rating) DESC LIMIT 10
)
)
Konštrukcia WITH WITH na sprehľadnenie zápisu SQL príkazov

Syntax

WITH
názov_1 [(stĺpec_1,..., stĺpec_n1)] AS (príkaz_1),
...
názov_m [(stĺpec_1,..., stĺpec_nm)] AS (príkaz_m)

hlavný_príkaz

kde príkaz_i a hlavný_príkaz môžú byť

SELECT ..., INSERT ..., UPDATE ..., DELETE ...


Konštrukcia WITH WITH na sprehľadnenie zápisu SQL príkazov

Vyhodnocovanie

I akokeby sme vytvorili dočasné tabuľky


I názov_i môžeme použiť v pozícii tabuľky
I príkaz_i môže používať všetky vyššie definované názvy
Konštrukcia WITH WITH na sprehľadnenie zápisu SQL príkazov

Motivácia – Cheme hercov, ktorí hrali v TOP 10 filmoch

I TOP filmy – podľa priemerného hodnotenia používateľmi


I hodnotenia obsahujú duplicity, cheme iba najnovšie hodnotenia

SELECT * FROM actors WHERE EXISTS


(SELECT NULL FROM plays
WHERE plays.actor_id = actors.id AND plays.film_id IN
(SELECT film_id FROM
(SELECT DISTINCT ON (user_id, film_id)
user_id, film_id, rating
FROM ratings ORDER BY user_id, film_id, time DESC
) AS tmp
GROUP BY film_id ORDER BY avg(rating) DESC LIMIT 10
)
)
Konštrukcia WITH WITH na sprehľadnenie zápisu SQL príkazov

Riešenie – Cheme hercov, ktorí hrali v TOP 10 filmoch

WITH dist_ratings AS (
SELECT DISTINCT ON (user_id, film_id)
user_id, film_id, rating
FROM ratings ORDER BY user_id, film_id, time DESC
),
top_10 AS (
SELECT film_id FROM dist_ratings
GROUP BY film_id ORDER BY avg(rating) DESC LIMIT 10
),
top_plays AS (
SELECT * FROM plays WHERE film_id IN (SELECT * FROM top_10)
)
SELECT * FROM actors WHERE EXISTS
(SELECT NULL FROM top_plays WHERE actor_id = id)
Konštrukcia WITH WITH na sprehľadnenie zápisu SQL príkazov

Pozor: Nefunguje to ako textové nahradzovanie

salaries
user_id year salary
1 2015 700
2 2015 1800
2 2014 1750
3 2014 320

WITH avg_salary AS (
SELECT avg(salary)
FROM salaries
)
SELECT avg_salary
Konštrukcia WITH WITH na sprehľadnenie zápisu SQL príkazov

Pri textovom nahradení by sme dostali

salaries
user_id year salary
1 2015 700
2 2015 1800
2 2014 1750
3 2014 320

SELECT (SELECT avg(salary)


FROM salaries)
Konštrukcia WITH WITH na sprehľadnenie zápisu SQL príkazov

Pri textovom nahradení by sme dostali

salaries
user_id year salary
1 2015 700
2 2015 1800
2 2014 1750
3 2014 320

SELECT (SELECT avg(salary)


FROM salaries)

avg
1142.50
Konštrukcia WITH WITH na sprehľadnenie zápisu SQL príkazov

Pozor: Nefunguje to ako textové nahradzovanie

salaries
user_id year salary
1 2015 700
2 2015 1800
2 2014 1750
3 2014 320

WITH avg_salary AS (
SELECT avg(salary)
FROM salaries
)
SELECT avg_salary

ERROR: column "avg_salary" does not exist


Konštrukcia WITH WITH na sprehľadnenie zápisu SQL príkazov

Čo sú tie stĺpce v zátvorkách?

WITH
názov_1 [(stĺpec_1,..., stĺpec_n1)] AS (príkaz_1)
hlavný_príkaz

sú to názvy stlpcov, nie argumenty


Konštrukcia WITH WITH na sprehľadnenie zápisu SQL príkazov

Čo sú tie stĺpce v zátvorkách?


salaries
user_id year salary
1 2015 700
2 2015 1800
2 2014 1750
3 2014 320
WITH avg_salary(my_year, my_salary) AS (
SELECT year, avg(salary)
FROM salaries
GROUP BY year
)
SELECT * from avg_salary
my_year my_salary
2014 1035
2015 1250
Konštrukcia WITH WITH na sprehľadnenie zápisu SQL príkazov

Takéto niečo teda nejde spraviť

salaries
user_id year salary
1 2015 700
2 2015 1800
2 2014 1750
3 2014 320

WITH avg_salary(in_year) AS (
SELECT avg(salary)
FROM salaries
WHERE year = in_year
)
SELECT avg_salary(2015) - avg_salary(2014)
Konštrukcia WITH WITH v kombinácii s INSERT, UPDATE, DELETE

INSERT, UPDATE, DELETE štandardne nevracajú nič

INSERT INTO data(a,b) values (1,1), (1,2)


Konštrukcia WITH WITH v kombinácii s INSERT, UPDATE, DELETE

Čo ak chceme vrátiť dáta?

RETURNING *
RETURNING výraz_1 AS názov_1, ..., výraz_n AS názov_n
I píšu sa na koniec príkazov INSERT, UPDATE, DELETE
Konštrukcia WITH WITH v kombinácii s INSERT, UPDATE, DELETE

INSERT RETURNING používa vkladané hodnoty

INSERT INTO data(a,b)


VALUES (1,1), (1,2)
RETURNING a * 2 AS x, b - 1 AS y

x y
2 0
2 1
Konštrukcia WITH WITH v kombinácii s INSERT, UPDATE, DELETE

DELETE RETURNING používa mazané hodnoty

data
a b
1 1
1 2

DELETE FROM data


WHERE b > 1
RETURNING b AS deleted_b

deleted_b
2
Konštrukcia WITH WITH v kombinácii s INSERT, UPDATE, DELETE

UPDATE RETURNING používa nové hodnoty

data
a b
1 1
1 2

UPDATE data
SET b = 3 * b
RETURNING b AS new_b

new_b
3
6
Konštrukcia WITH WITH v kombinácii s INSERT, UPDATE, DELETE

Príklad: potrebujeme zistiť automaticky vložené id

CREATE TABLE users (


id SERIAL,
name VARCHAR
)

INSERT INTO users (name)


VALUES (’john’)
RETURNING id

id
1
Konštrukcia WITH WITH v kombinácii s INSERT, UPDATE, DELETE

Príklad: Nové hodnoty chceme zaznamenať ako históriu

CREATE TABLE users ( CREATE TABLE salary_history (


id SERIAL, user_id SERIAL,
name VARCHAR, date date,
salary numeric salary numeric
) )

INSERT INTO salary_history (user_id, date, salary)


UPDATE users
SET salary = 1.1 * salary
RETURNING id, current_date, salary
Konštrukcia WITH WITH v kombinácii s INSERT, UPDATE, DELETE

Problém

Takto sa to ale nedá, nakoľko INSERT INTO akceptuje iba SELECT


Konštrukcia WITH WITH v kombinácii s INSERT, UPDATE, DELETE

Neúspešná oprava

CREATE TABLE users ( CREATE TABLE salary_history (


id SERIAL, user_id SERIAL,
name VARCHAR, date date,
salary numeric salary numeric
) )

INSERT INTO salary_history (user_id, date, salary)


SELECT * FROM (
UPDATE users
SET salary = 1.1 * salary
RETURNING id, current_date, salary
)
Konštrukcia WITH WITH v kombinácii s INSERT, UPDATE, DELETE

Problém

Aj toto zlyhá, nakoľko UPDATE nie je SELECT


Konštrukcia WITH WITH v kombinácii s INSERT, UPDATE, DELETE

Riešenie: Treba použiť WITH

WITH
...
názov_i ... AS (príkaz_i),
...
hlavný_príkaz

kde príkaz_i a hlavný_príkaz môžú byť

SELECT ..., INSERT ..., UPDATE ..., DELETE ...


Konštrukcia WITH WITH v kombinácii s INSERT, UPDATE, DELETE

Riešenie: Treba použiť WITH

CREATE TABLE users ( CREATE TABLE salary_history (


id SERIAL, user_id SERIAL,
name VARCHAR, date date,
salary numeric salary numeric
) )

WITH updated_salaries AS (
UPDATE users
SET salary = 1.1 * salary
RETURNING id, current_date, salary
)
INSERT INTO salary_history (user_id, date, salary)
SELECT * FROM updated_salaries
Základné info o texte

Section 24

Základné info o texte


Základné info o texte

Čo je to text?

Text je postupnosť znakov


Základné info o texte

Ako ho zakódovať v počítači?

Ako postupnosť bitov


Základné info o texte

Ako ho zakódovať v počítači?

1. každému znaku priradíme číslo – code point


2. každé číslo zakódujeme ako postupnosť bitov – code unit
Základné info o texte

Unicode

Unicode je jedno konkrétne priradenie code point jednotlivým znakom

Napr:

latinkové A → 65
čínsky znak pre číslo jedna → 19968
základný smajlík → 128528

V súčasnosti definuje 128 237 znakov (čísla nie sú obsadené spojito)


Základné info o texte

UTF-32

Zakóduje každý Unicode code point ako postupnosť 32 bitov (code unit).

I latinka a základné znaky majú code point ≤ 127


I zmestia sa do 8 bitov
I UTF-32 kódovanie obsahuje veľa núl
Základné info o texte

UTF-8

Zakóduje každý Unicode code point ako postupnosť 8, 16, 24, alebo 32
bitov.
I latinka a základné znaky sa kódujú pomocou 8 bitov,
I ostatné s viac bitmi
Základné info o texte

UTF-16

Zakóduje každý Unicode code point ako postupnosť 16 alebo 32 bitov.


Základné info o texte

Príklad

den
znaky d e n
Unicode code points 100 101 110
UTF-16 code units 0x0064 0x0065 0x006E 48 bitov
UTF-8 code units 0x64 0x65 0x6E 24 bitov

deň
Znaky d e ň
Unicode code points 100 101 328
UTF-16 code units 0x0064 0x0065 0x0148 48 bitov
UTF-8 code units 0x64 0x65 0xC588 32 bitov
Základné info o texte

Font

Font cca definuje mapovanie z code pointu na obrázok (glyph).


Základné info o texte

Čo je to znak? – Komplikácia č. 1

Ten istý používateľom vnímaný reťazec môže byť zakódovaný rôznymi


znakmi:
deň
Znaky d e ň
Unicode code points 100 101 328

Znaky d e n ˇ
Unicode code points 100 101 110 780
Základné info o texte

Kanonické formy

Unicode definuje viacero kanonických foriem a transformácií, ktoré majú


zabezpečiť, aby reťazec bol kódovaný tou istou postupnosťou code points:
CFC
d e ň → d e ň

d e n ˇ → d e ň
Základné info o texte

Čo je to znak? – Komplikácia č. 2

V prirodzenom jazyku môže byť tá istá vec raz jeden, inokedy viac znakov
Základné info o texte

ch

Písmená ch, dz, dž sa nazývajú zložky. Skladajú sa z dvoch písmen


abecedy, ale súčasne tvoria jeden znak – jedno samostatné písmeno
slovenskej abecedy, ktorým sa zapisuje jedna hláska (spoluhláska)

https://jazykovaporadna.sme.sk/q/5858/#ixzz5YkHCQGk6
Základné info o texte

ch

chlapec – ch, l, a, p, e, c – dĺžka 6 písmen (nie 7)


viachlasný – v, i, a, c, h, l, a, s, n, ý – dĺžka 10 písmen (nie 9)
Základné info o texte

Čo je to znak? – Záver

I Pojem znak je veľmi voľný. Seriózne narábanie s textom je netriviálne.


I Bežné knižnice pod pojmom znak myslia typicky code point.
Základné info o texte

Ďalšie kódovania

I ISO/IEC 8859
I CP 1250
I atď.

I priradzujú znakom iné code point čísla


I kóduju ich na bity trochu ináč
I na rozdiel od Unicode (a UTF) definujú iba nejakú podmnožinu znakov

I potom nevieme niektoré znaky zapísať


I v súčasnej dobe sa im treba vyhnúť
Základné info o texte

PostgreSQL a kódovania

I podporuje ich veľa


https://www.postgresql.org/docs/current/multibyte.html
I defaultne kókovanie sa nastavuje pri inštalácii
I pri vytváraní databázy sa dá zvoliť iné kódovanie

I na cviku používame UTF-8


Textové typy

Section 25

Textové typy
Textové typy Znak

Znak

Dátový typ pre znak neexistuje


Textové typy char(n)

char(n)

I reťazec dĺžky presne n znakov


I kratšie reťazce sú doplnené sprava medzerami na dĺžku n znakov
I ak n neuvedieme, je to to isté ako char(1)
I maximálne môže zaberať 1GB (1 znak môže zaberať aj viac bajtov)

I pri práci s nimi sú medzery sprava ignorované (aj keď sme ich zadali
ručne)
Textové typy char(n)

char(n)

CREATE TABLE test(


x char(5)
);

INSERT INTO test(x) VALUES


(’ a ’),
(’ a’);

SELECT count(*) FROM test WHERE x = ’ a’;


Textové typy char(n)

char(n)

CREATE TABLE test(


x char(5)
);

INSERT INTO test(x) VALUES


(’ a ’),
(’ a’);

SELECT count(*) FROM test WHERE x = ’ a’;

count
2
Textové typy char(n)

char(n)

Typ char(n) preto nepoužívajte – koledujete si iba o problémy


Textové typy varchar(n)

varchar(n)

I reťazec dĺžky maximálne n znakov


I kratšie reťazce zeberajú menej miesta
I ak n neuvedieme, dĺžka reťazca nie je obmedzená (PostgreSQL
špecialita)

I žiadna mágia s medzerami na konci reťazca


Textové typy varchar(n)

varchar(n)

CREATE TABLE test(


x varchar(5)
);

INSERT INTO test(x) VALUES


(’ a ’),
(’ a’);

SELECT count(*) FROM test WHERE x = ’ a’;

count
1
Textové typy text

text

I reťazec bez obmedzenia dĺžky


I kratšie reťazce zeberajú menej miesta
I nie je v SQL štandarde, ale väčšina DB systémov ho má
Textové typy text

PostgreSQL – varchar vs text

I interne existuje iba jedna implementácia


Textové typy text

varchar a text a bezpečnosť

I nevhodné na dáta, ktoré pochádzajú z nebezpečného zdroja, napr. od


používateľa
I môže vám zaplniť miesto na disku vkladaním veľmi dlhých reťazcov
Práca s textom

Section 26

Práca s textom
Práca s textom Zreťazenie reťazcov

Operátor || – Zreťazenie reťazcov

reťazec_1 || reťazec_2

I vracia dátový typ TEXT

SELECT name,
email,
name || ’ (’ || email || ’)’ AS extended_name
FROM users

name email extended_name


fan123 fan123@gmail.com fan123 (fan123@gmail.com)
johnny spam@spam.com johnny (spam@spam.com)
Práca s textom Zreťazenie reťazcov

Operátor || – NULLy

reťazec_1 || reťazec_2

I ak je jeden z reťazcov NULL, potom je výsledok NULL


Práca s textom Zreťazenie reťazcov

Operátor || – Zreťazenie s nereťazcom

reťazec || nereťazec

I nereťazec skonvertuje na reťazec a zreťazí ich

SELECT ’text’ || 68

?column?
text68
Práca s textom Zreťazenie reťazcov

Operátor || – Prvý operand musí byť reťazec

SELECT 32 || 68

Dostaneme chybu

HINT: No operator matches the given name and argument


type(s). You might need to add explicit type casts.
Práca s textom Zreťazenie reťazcov

Operátor || – Prvý operand musí byť reťazec

SELECT 32::TEXT || 68

?column?
3268
Práca s textom Dĺžka reťazca

Dĺžka reťazca

length(reťazec)

I vráti počet znakov v reťazci


I vracia dátový typ INTEGER
I ak je reťazec NULL, vráti NULL
Práca s textom Dĺžka reťazca

Dĺžka reťazca

SELECT length(’Toto je reťazec dlhý 30 znakov’)

length
30
Práca s textom Úprava reťazcov

Funkcia lower

lower(reťazec)

I konvertuje vstupný reťazec na malé písmená

SELECT lower(’dvojHrbá Ťava’)

lower
dvojhrbá ťava
Práca s textom Úprava reťazcov

Funkcia upper

upper(reťazec)

I konvertuje vstupný reťazec na veľké písmená

SELECT upper(’dvojHrbá Ťava’)

upper
DVOJHRBÁ ŤAVA
Práca s textom Úprava reťazcov

Funkcie lower, upper - Case-insensitive porovnávanie


reťazcov

SELECT * FROM films


WHERE lower(name) = lower(’Django unchained’)

K efektívnosti sa ešte dostaneme


Práca s textom Úprava reťazcov

Funkcia position

position(reťazec_1 in reťazec_2)

I vráti pozíciu prvého výskytu (zľava) reťazca_1 v rámci reťazca_2


I vracia dátový typ INTEGER
I počíta sa od čísla 1
I ak sa reťazec_1 v reťazci_2 nenachádza, vráti číslo 0
Práca s textom Úprava reťazcov

Funkcia position

SELECT position(’to’ in ’Tato, ta to čo toto’)

position
3

SELECT position(’tt’ in ’Tato, ta to čo toto’)

position
0
Práca s textom Úprava reťazcov

Funkcia substring

substring(reťazec [from začiatok] [for dĺžka])

I vráti podreťazec danej dĺžky začínajúci na danej pozícii


I ak je aspoň jeden z argumentov NULL, výsledok je NULL

SELECT substring(’jeden dva tri’ from 3 for 7)

substring
den dva
Práca s textom Úprava reťazcov

Funkcia substring – Záporná dĺžka

Ak je parameter dĺžka záporný, dostaneme chybu:

ERROR: negative substring length not allowed


Práca s textom Úprava reťazcov

Funkcia substring – Neexistujúce pozície

I funkcia pracuje aj s neexistujúcimi pozíciami, t.j. pred a za reťazcom


I do výsledného reťazca pre ne ale nedáva žiadne znaky

SELECT substring(’text’ from -1 for 4)

substring
te

SELECT length(substring(’text’ from -1 for 4))

length
2
Práca s textom Úprava reťazcov

Funkcia repeat

repeat(reťazec, n)

I zopakuje zadaný reťazec n-krát


I ak je n ≤ 0, vráti prázdny reťazec

Napr. chceme získať hodnotenie filmu vo forme hviezdičiek

SELECT film_id, repeat(’*’, rating) as rating


FROM rating
Práca s textom Odstraňovanie diakritiky

Funkcia unaccent

unaccent(reťazec)

I vráti reťazec, v ktorom sú znaky s diakritikou nahradené ekvivalentmi


bez diakritiky

SELECT unaccent(’článok’)

unaccent
clanok
Práca s textom Odstraňovanie diakritiky

Funkcia unaccent – Rozšírenie unaccent

I funkcia unaccent sa nachádza v rozšírení unaccent


I najprv musíme rozšírenie nainštalovať do databázy

CREATE EXTENSION unaccent [SCHEMA názov_schémy]

I v zásade to spustí nejaký skript, ktorý vytvorí v danej schéme vhodné


objekty
I môže to spraviť iba používateľ s dostatočnými právami
I ak schéma nie je zadaná, berie sa schéma public
I v jednej databáze môže byť jedno rozšírenie nainštalované iba raz
Práca s textom Odstraňovanie diakritiky

Porovnávanie reťazcov bez ohľadu na diakritiku

SELECT * FROM user


WHERE unnacent(name) = unaccent(’Tomáš’)

K efektívnosti sa ešte dostaneme


Práca s textom Testovanie vzorov (Pattern matching)

Testovanie vzorov (Pattern matching)

I reťazce nemusíme porovnávať iba na presnú zhodu


I môžeme aj testovať, či sa reťazec podobá na zadaný vzor

PostgreSQL ponúka možnosti:


I operátor LIKE
I operátor SIMILAR TO
I POSIXovské regulárne výrazy
Práca s textom Testovanie vzorov (Pattern matching)

Operátor LIKE

reťazec LIKE vzor

I vráti TRUE/FALSE podľa toho, či sa reťazec podobá na vzor


I ak reťazec alebo vzor je NULL, vráti NULL

Vzor je reťazec, v ktorom majú niektoré znaky špeciálny význam:


I _ (podčiarkovník) – nahrádza ľubovoľný znak
I % – nahrádza ľubovoľnú, aj prázdnu, postupnosť znakov
Práca s textom Testovanie vzorov (Pattern matching)

Operátor LIKE – Príklad

’písmeno A’ LIKE ’písmeno A’ → TRUE


’písmeno A’ LIKE ’písmeno _’ → TRUE
’písmeno AB’ LIKE ’písmeno _’ → FALSE
’písmeno AB’ LIKE ’písmeno %’ → TRUE
’písmeno ’ LIKE ’písmeno %’ → TRUE
’písmeno ’ LIKE ’písmeno _%’ → FALSE
’písmeno A’ LIKE ’písmeno _%’ → TRUE
’písmeno _’ LIKE ’písmeno A’ → FALSE
Práca s textom Testovanie vzorov (Pattern matching)

Operátor LIKE – Príklad

Chceme získať všetkých používateľov, ktorí si ako meno zadali email.

SELECT * FROM users


WHERE name LIKE ’%@%.%’
Práca s textom Testovanie vzorov (Pattern matching)

Operátor LIKE – Zrušenie špeciálneho významu _ a %

I napr. chceme vzor, v ktorom sú dva ľubovoľné znaky oddelené


podtržníkom
I podtržník má ale špeciálny význam
I aby sa podtržník zo vzoru zhodoval iba s podtržníkom, musíme ho
predradiť lomítkom \

’A_B’ LIKE ’_\__’ → TRUE


’ACB’ LIKE ’_\__’ → FALSE

’A_B’ LIKE ’___’ → TRUE


’ACB’ LIKE ’___’ → TRUE
Práca s textom Testovanie vzorov (Pattern matching)

Operátor LIKE – Zrušenie špeciálneho významu \

I lomítko \ má teda tiež špeciálny význam


I ak ho chceme zbaviť špeciálneho významu, musíme predradiť ďalším
lomítkom: \\
Práca s textom Testovanie vzorov (Pattern matching)

Operátor ILIKE

reťazec ILIKE vzor

I funguje rovnako ako LIKE s tým rozdielom, že


I neberie do úvahy veľkosť písmen
I nie je súčasťou SQL štandardu

’A’ LIKE ’a’ → FALSE


’A’ ILIKE ’a’ → TRUE
Práca s textom Testovanie vzorov (Pattern matching)

Operátor SIMILAR TO

reťazec SIMILAR TO vzor


reťazec NOT SIMILAR TO vzor

I funguje podobne ako LIKE


I vzor je ale SQL-kový regulárny výraz
Práca s textom Testovanie vzorov (Pattern matching)

SQL-kový regulárny výraz

_ nahrádza ľubovoľný znak


% nahrádza ľubovoľnú, aj prázdnu, postupnosť znakov
Práca s textom Testovanie vzorov (Pattern matching)

SQL-kový regulárny výraz

| uvádza alternatívy – aspoň jedna sa musí zhodnúť

’a’ SIMILAR TO ’a|b’ → TRUE


’b’ SIMILAR TO ’a|b’ → TRUE
” SIMILAR TO ’a|b’ → FALSE
’ab’ SIMILAR TO ’a|b’ → FALSE
Práca s textom Testovanie vzorov (Pattern matching)

SQL-kový regulárny výraz

guľaté zátvorky () vytvárajú jeden logický celok

’a’ SIMILAR TO ’a|bc’ → TRUE


’bc’ SIMILAR TO ’a|bc’ → TRUE
’ac’ SIMILAR TO ’a|bc’ → FALSE
’ac’ SIMILAR TO ’(a|b)c’ → TRUE
Práca s textom Testovanie vzorov (Pattern matching)

SQL-kový regulárny výraz

* označuje, že predchádzajúci prvok (zo vzoru) bude nula alebo viackrát

’aa’ SIMILAR TO ’a*’ → TRUE


” SIMILAR TO ’a*’ → TRUE
’ab’ SIMILAR TO ’(a|b)*’ → TRUE
Práca s textom Testovanie vzorov (Pattern matching)

SQL-kový regulárny výraz

+ označuje, že predchádzajúci prvok (zo vzoru) bude raz alebo viackrát

’aa’ SIMILAR TO ’a+’ → TRUE


” SIMILAR TO ’a+’ → FALSE
Práca s textom Testovanie vzorov (Pattern matching)

SQL-kový regulárny výraz

? označuje, že predchádzajúci prvok (zo vzoru) bude nula alebo jedenkrát

’aa’ SIMILAR TO ’a?’ → FALSE


’a’ SIMILAR TO ’a?’ → TRUE
” SIMILAR TO ’a?’ → TRUE
Práca s textom Testovanie vzorov (Pattern matching)

SQL-kový regulárny výraz

{m} označuje, že predchádzajúci prvok (zo vzoru) bude presne m-krát

’aaa’ SIMILAR TO ’a{2}’ → FALSE


’aa’ SIMILAR TO ’a{2}’ → TRUE
’a’ SIMILAR TO ’a{2}’ → FALSE
Práca s textom Testovanie vzorov (Pattern matching)

SQL-kový regulárny výraz

{m,} označuje, že predchádzajúci prvok (zo vzoru) bude m alebo viackrát

’aaa’ SIMILAR TO ’a{2,}’ → TRUE


’aa’ SIMILAR TO ’a{2,}’ → TRUE
’a’ SIMILAR TO ’a{2,}’ → FALSE
Práca s textom Testovanie vzorov (Pattern matching)

SQL-kový regulárny výraz

{m,n} označuje, že predchádzajúci prvok (zo vzoru) bude m až n-krát

’aaaa’ SIMILAR TO ’a{2,3}’ → FALSE


’aaa’ SIMILAR TO ’a{2,3}’ → TRUE
’aa’ SIMILAR TO ’a{2,3}’ → TRUE
’a’ SIMILAR TO ’a{2,3}’ → FALSE
Práca s textom Testovanie vzorov (Pattern matching)

SQL-kový regulárny výraz

[] definujú množinu znakov, z ktorých aspoň jeden sa musí zhodovať so


vstupom

’a’ SIMILAR TO ’[azn]’ → TRUE


’z’ SIMILAR TO ’[azn]’ → TRUE
’n’ SIMILAR TO ’[azn]’ → TRUE
’x’ SIMILAR TO ’[azn]’ → FALSE
Práca s textom Testovanie vzorov (Pattern matching)

SQL-kový regulárny výraz

I [] môže obsahovať aj rozsah hodnôt


I rozsah sa udáva cez pomlčku
I môžeme použiť viac rozsahov súčasne

’a’ SIMILAR TO ’[b-dg-k]’ → FALSE


’e’ SIMILAR TO ’[b-dg-k]’ → FALSE
’c’ SIMILAR TO ’[b-dg-k]’ → TRUE
’k’ SIMILAR TO ’[b-dg-k]’ → TRUE

I rozsah je závislý od toho, aký jazyk je nastavený v databáze


I jeho použitie vedie na neprenosný program
Práca s textom Testovanie vzorov (Pattern matching)

SQL-kový regulárny výraz

I ak [] obsahuje ako prvý znak ^, chápe sa to ako doplnok množiny

’a’ SIMILAR TO ’[^b-dg-k]’ → TRUE


’e’ SIMILAR TO ’[^b-dg-k]’ → TRUE
’c’ SIMILAR TO ’[^b-dg-k]’ → FALSE
’k’ SIMILAR TO ’[^b-dg-k]’ → FALSE
Práca s textom Testovanie vzorov (Pattern matching)

Príklad – Kontrola emailovej adresy

CREATE TABLE users (


id serial,
email varchar
CHECK(email SIMILAR TO ’[a-z0-9.]+@[a-z.0-9]+.[a-z]+’)
)
Fulltextové vyhľadávanie

Section 27

Fulltextové vyhľadávanie
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie

Je to operátor, ktorý testuje, či text dokumentu vyhovuje zadanému


dopytu, napr. obsahuje dané slová.

Od takéhoto operátora štandardne očakávame, aby


I bral do úvahy rôzne tvary slov – jednotné vs množné číslo,
skloňovanie, časovanie, ...
I ignoroval tzv. stop slová – slová a iné znaky, ktoré o obsahu
dokumentu veľa nepovedia, napr. spojky, predložky, čiarky, ...
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – tsvector

tsvector
I dátový typ, ktorý predstavuje spracovaný text, nad ktorým môžeme
spustiť fulltextové vyhľadávanie

to_tsvector(text)
I funkcia, ktorá text skonvertuje na tsvector
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – tsvector

SELECT to_tsvector(’a fat cat ate fat rats’)

to_tsvector
’ate’:4 ’cat’:3 ’fat’:2,5 ’rat’:6
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – tsquery

tsquery
I dátový typ, ktorý predstavuje dopyt, ktorý chceme nad textom
vyhodnotiť

to_tsquery(dopyt)
I funkcia, ktorá dopyt (text) v špeciálnom tvare skonvertuje na tsquery
I dopyt tvoria slová pospájané:
I booleovskými operátormi: & (AND), | (OR), ! (NOT)
I okruhlými zátvorkami: ( )
I slová sú normalizované
I stop slová sú vyhodené
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – tsquery

SELECT to_tsquery(’fat & (rat | bird)’)

to_tsquery
’fat’ & ( ’rat’ | ’bird’ )
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – tsquery

plainto_tsquery(dopyt)
I funkcia, ktorá čístý text bez operátorov skonvertuje na tsquery
I jednotlivé slová sú vo výsledku pospájané operátorom & (AND)
I slová sú normalizované
I stop slová sú vyhodené
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – tsquery

SELECT plainto_tsquery(’fat rat bird’)

plainto_tsquery
’fat’ & ’rat’ & ’bird’
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – tsquery

SELECT plainto_tsquery(’fat & ( rat | bird)’)

plainto_tsquery
’fat’ & ’rat’ & ’bird’
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – Operátor @@

tsvector @@ tsquery
tsquery @@ tsvector

I vráti TRUE/FALSE podľa toho, či daný dokument spĺňa daný dopyt


Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – Operátor @@

SELECT to_tsvector(’a fat cat ate fat rats’)


@@ to_tsquery(’fat & (rat | bird)’)

?column?
TRUE

SELECT to_tsvector(’a fat cat ate fat rats’)


@@ to_tsquery(’fat & bird’)

?column?
FALSE
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie

CREATE TABLE articles


(
id serial,
title varchar(50),
perex varchar(255),
content text
)

SELECT *
FROM articles
WHERE to_tsvector(content)
@@ to_tsquery(’fat & (rat | bird)’)
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – Rank

ts_rank(tsvector, tsquery)

I vracia číslo
I čím je väčšie, tým je dokument relevantnejší pre daný dopyt
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – Rank

SELECT
ts_rank(to_tsvector(’’), to_tsquery(’text’)),
ts_rank(to_tsvector(’text’), to_tsquery(’text’)),
ts_rank(to_tsvector(’text text’), to_tsquery(’text’)),
ts_rank(to_tsvector(’text text text’), to_tsquery(’text’))

ts_rank ts_rank ts_rank ts_rank


0 0.0607927 0.0759909 0.0827456
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie

SELECT *
FROM articles
WHERE to_tsvector(content)
@@ to_tsquery(’fat & (rat | bird)’)
ORDER BY ts_rank(to_tsvector(content),
to_tsquery(’fat & (rat | bird)’)) DESC
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – Jazyk

Fulltextové vyhľadávanie je jazykovo závislé:


I transformovanie slov na ich základný tvar
I ktoré slová sú stop words
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – Nastavenie vyhľadávania

I tieto veci sú dané nastaveniami vyhľadávania


I PostgreSQL má štandardne tieto:
I jazykovo špecifické: danish, dutch, english, finnish, french, german,
hungarian, italian, norwegian, portuguese, romanian, russian, spanish,
swedish, turkish
I jazykovo nezávislé: simple
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – Nastavenie vyhľadávania

to_tsvector(text)
to_tsquery(text)
plainto_tsquery(text)

I nastavenie vyhľadávania je dané nastavením PostgreSQL


default_text_search_config
I nastavuje sa v konfiguračnom súbore
I za behu sa dá nastaviť SET default_text_search_config =
hodnota
I za behu sa dá zistiť SHOW default_text_search_config
I náš server má hodnotu english
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – Nastavenie vyhľadávania

to_tsvector(config, text)
to_tsquery(config, text)
plainto_tsquery(config, text)

I ako prvý parameter berú názov nastavenia vyhľadávania

SELECT to_tsvector(’spanish’, ’dos cervezas por favor’)

to_tsvector
’cervez’:2 ’dos’:1 ’favor’:4
Fulltextové vyhľadávanie

Fulltextové vyhľadávanie – Nastavenie vyhľadávania simple

I netransformuje slová na základný tvar


I za stop slová považuje čiarky, bodky a pod., no žiadne slová

SELECT to_tsvector(’english’, ’a dog, cats’),


to_tsvector(’simple’, ’a dog, cats’)

to_tsvector to_tsvector
cat’:3 ’dog’:2 ’a’:1 ’cats’:3 ’dog’:2
Práca s dátumom a časom

Section 28

Práca s dátumom a časom


Práca s dátumom a časom Dátumové a časové typy podrobne

Dátum bez času

date
I 4 bajty
I od 4717 p.n.l. po 5874897 n.l.

Dátumový literál

DATE ’YYYY-MM-DD’

17. jún 2015:

DATE ’2015-06-17’
Práca s dátumom a časom Dátumové a časové typy podrobne

Čas bez dátumu

time
I 8 bajtov
I od 0:00:00 do 24:00:00 vrátane
Práca s dátumom a časom Dátumové a časové typy podrobne

Časový literál

Formát

TIME ’HH:MM:SS.SSSSSS’

Prvá milisekunda po odchode poslednej 39ky z Mlynskej

TIME ’23:05:00.000001’
Práca s dátumom a časom Dátumové a časové typy podrobne

Čas 00:00 vs 24:00

CREATE TABLE test (


x time
)

INSERT INTO test (x)


VALUES
(TIME ’00:00:00’),
(TIME ’24:00:00’)

x
00:00:00
24:00:00

00:00:00 < 24:00:00


Práca s dátumom a časom Dátumové a časové typy podrobne

Použitie

schedule
day start end activity
Monday 00:00 02:00 film watching
Monday 22:00 24:00 film watching
Práca s dátumom a časom Dátumové a časové typy podrobne

Dátum s časom

timestamp
I 8 bajtov
I rozsahy rovnako ako pri dátume a čase
I interne reprezentovaný ako počet sekúnd od nejakého pevného času

Literál dátumu s časom:

TIMESTAMP ’YYYY-MM-DD HH:MM:SS.SSSSSS’


Práca s dátumom a časom Dátumové a časové typy podrobne

Dátum a čas 00:00 vs 24:00

CREATE TABLE test (


x timestamp
)

INSERT INTO test (x)


VALUES
(TIMESTAMP ’2015-06-17 00:00:00’),
(TIMESTAMP ’2015-06-16 24:00:00’)

x
2015-06-17 00:00:00
2015-06-17 00:00:00

TIMESTAMP ’2015-06-17 00:00:00’ = TIMESTAMP ’2015-06-16


24:00:00’
Práca s dátumom a časom Dátumové a časové typy podrobne

Varianty s časovou zónou

I timestamp with time zone


I time with time zone
Práca s dátumom a časom Dátumové a časové typy podrobne

Časový úsek bez ohľadu na začiatok a koniec

interval

I 16 bajtov
I od -178000000 rokov po 178000000 rokov
Práca s dátumom a časom Dátumové a časové typy podrobne

Časový úsek bez ohľadu na začiatok a koniec

INTERVAL ’počet jednotka [počet jednotka ...]’

Jednotky
microsecond millisecond second
minute hour day
week month year
decade century millennium

INTERVAL ’1 year 2 weeks 7 minutes’


Práca s dátumom a časom Dátumová a časová aritmetika

Dátumová a časová aritmetika – Big Picture

bod ± interval → bod posúva bod v čase


bod + bod → × nedáva zmysel
bod − bod → interval časový úsek medzi bodmi
interval ± interval → interval sčíta/odčíta intervaly
interval ∗/ číslo → interval naškáluje interval
Práca s dátumom a časom Dátumová a časová aritmetika

Dátumová a časová aritmetika – Nejednotnosť

date ± integer → date


I dátum posunie dopredu/dozadu o daný počet dní

timestamp ± integer → ×
time ± integer → ×
I taký operátor nie je
Práca s dátumom a časom Dátumová a časová aritmetika

Dátumová a časová aritmetika – Nejednotnosť

date ± interval → timestamp


timestamp ± interval → timestamp
I dátumočas posunie dopredu/späť o daný interval
I dátum (date), sa považuje za dátumočas s časovou zložkou 00:00:00
I výsledok je timestamp bez ohľadu či má interval časovú zložku

time ± interval → time


I čas posunie dopredu/dozadu o daný interval
I dátumovú zložku intervalu ignoruje
I TIME ’01:02:03’ + ’5 days 1 second’ = TIME ’01:02:04’
I TIME ’01:02:03’ - ’5 days 1 second’ = TIME ’01:02:02’
Práca s dátumom a časom Dátumová a časová aritmetika

Dátumová a časová aritmetika – Podrobne

I viď dodatok
Práca s dátumom a časom Dátumové a časové funkcie

Aktuálny dátum a čas

current_date → date
I vráti aktuálny dátum

localtime → time
I vráti aktuálny čas

localtimestamp → timestamp
I vráti aktuálny dátum a čas
Práca s dátumom a časom Dátumové a časové funkcie

Vytvorenie dátumu a času

make_date(rok, mesiac, deň) → date


I vytvorí zadaný dátum

make_time(hodina, minúta, sekunda) → time


I vytvorí zadaný čas

make_timestamp(rok, mesiac, deň, hodina, minúta, sekunda) →


timestamp
I vytvorí zadaný dátum a čas

make_interval(roky, mesiace, týždne, dni, hodiny, minúty,


sekundy) → interval
I vytvorí zadaný interval
Práca s dátumom a časom Dátumové a časové funkcie

Získanie časti dátumu, času a intervalu

date_part(časť, timestamp) → double precision


date_part(časť, interval) → double precision
I získa zadanú časť dátumočasu/intervalu
I dátum/čas sa konvertujú na dátumočas

SELECT date_part(’month’, TIMESTAMP ’2015-04-07 12:56:34’)

date_part
4
Práca s dátumom a časom Dátumové a časové funkcie

Získanie časti dátumu, času a intervalu

Ako časť môžu byť hodnoty


century day decade
dow (deň týždňa) doy (deň roka) epoch
hour isodow (deň týžňa od Po) isoyear (od Po)
microseconds millennium milliseconds
minute month quarter (štvrťrok)
second week (od Po) year
Práca s dátumom a časom Dátumové a časové funkcie

Získanie časti dátumu, času a intervalu

date_trunc(časť, timestamp) → timestamp


date_trunc(časť, interval) → timestamp
I odreže dátumočas/interval po danú časť
I dátum/čas sa konvertujú na dátumočas

SELECT date_trunc(’month’, TIMESTAMP ’2015-04-07 12:56:34’)

date_trunc
2015-04-01 00:00:00
Práca s dátumom a časom Dátumové a časové funkcie

Získanie časti dátumu, času a intervalu

Ako časť môžu byť hodnoty


microseconds milliseconds second
minute hour day
week (od Po) month quarter
year decade century
millennium
Práca s dátumom a časom Dátumové a časové funkcie

Získanie časti dátumu, času a intervalu – Príklad

orders
id time_of_order amount
1 2015-02-05 12:49:00 10
2 2015-02-06 12:50:00 15

SELECT date_trunc(’week’, time_of_order) as week,


sum(amount)
FROM orders
GROUP BY week

week sum
2015-02-02 00:00:00 25
Práca s dátumom a časom Dátumové a časové funkcie

Získanie časti dátumu, času a intervalu – Príklad

orders
id time_of_order amount
1 2015-02-05 12:49:00 10
2 2015-02-06 12:50:00 15

SELECT date_part(’year’, time_of_order) as year,


date_part(’week’, time_of_order) as week,
sum(amount)
FROM orders
GROUP BY year, week

year week sum


2015 6 25
Náhodné čísla

Section 29

Náhodné čísla
Náhodné čísla

Náhodné čísla

random()

I vráti náhodné desatinné číslo z intervalu h0.0, 1.0),


I číslo je typu double precision,
I rovnomerná distribúcia.

SELECT random()

random
0.216747856233269
Náhodné čísla

Náhodné čísla – Zmena intervalu

Ak chceme náhodné čísla z intervalu hmin, max), musíme pôvodný rozsah


naškálovať.

random() * (max - min) + min


Náhodné čísla

Náhodné čísla – Celé čísla

Ak chceme, aby boli náhodné čísla celé, musíme ich vhodne konvertovať:
I funkcia floor(x)
I funkcia ceil(x)
I funkcia trunc(x)
I funkcia round(x)
I CAST
Náhodné čísla

Náhodné čísla – Celé čísla – Funkcia floor

floor(x)

I zaokrúhli číslo na najbližie menšie celé číslo


I floor(1.5) = 1
I floor(-1.5) = -2

floor(random() * (max - min) + min)

I dáva potom celé čísla z rozsahu hmin, max)


Náhodné čísla

Náhodné čísla – Celé čísla – Funkcia ceil

ceil(x)

I zaokrúhli číslo na najbližie väčšie celé číslo


I ceil(1.5) = 2
I ceil(-1.5) = -1

ceil(random() * (max - min) + min)

I dáva potom celé čísla z rozsahu hmin, maxi


I získať ale číslo min je prakticky nemožné, nakoľko ho dostaneme, iba
ak random() vráti presne číslo 0.0
I nakoľko to ale nie je vylúčené, takýto vzťah negeneruje čísla s
rovnomernou pravdepodobnosťou
Náhodné čísla

Náhodné čísla – Celé čísla – Funkcia trunc

trunc(x)
I odreže desatinnú časť
I trunc(1.5) = 1
I trunc(-1.5) = -1

trunc(random() * (max - min) + min)


I ak je min < 0, tak min bude vygenerované iba ak random vygeneruje
presne 0.0, čo sa stane s nízkou pravdepodobnosťou
I ak je min > 0, tak sa vygeneruje s dobrou pravdepodobnosťou
I ak je max > 0, tak nebude nikdy vygenerované
I ak je max ≤ 0, tak sa vygeneruje s dobrou pravdepodobnosťou
I takýto výraz sa správa rôzne v závislosti od toho, či pracujeme s
kladnými alebo zápornými číslami
Náhodné čísla

Náhodné čísla – Celé čísla – Funkcia round

round(x)

I zaokrúhli desatinné číslo na celé číslo podľa bežných pravidiel


zaokrúhľovania

round(random() * (max - min) + min)

I dáva potom celé čísla z rozsahu hmin, maxi


I kedže čísla min a max vzniknú iba zaokruhľovaním z jednej strany,
pravdepodobnosť ich vzniku je polovičná než ostatných čísel
I tým pádom takýto vzťah negeneruje čísla s rovnomernou
pravdepodobnosťou
Náhodné čísla

Náhodné čísla – Celé čísla – CAST

CAST (x AS integer)

I pretypuje x na celé číslo,


I zároveň zaokrúhli x podľa bežných pravidiel zaokruhľovania
I situácia je podobná ako v prípade round
Náhodné čísla

Náhodné čísla – Celé čísla – Záver

Používajte variant floor


Náhodné čísla

Náhodné čísla – Celé čísla – Typ

I floor a iné funkcie vracajú rovnaký dátový typ ako majú na vstupe

floor(random() * (max - min) + min)


I je síce celé číslo,
I ale dátového typu double precision

Ak chceme typ integer, treba pretypovať


I floor(random() * (max - min) + min)::integer
Náhodné čísla

Náhodné čísla – Komplikácia

Chceme náhodné číslo a zároveň jeho dvojnásobok

SELECT random() AS x, x * 2 AS y

ERROR: column "x" does not exist


Náhodné čísla

Náhodné čísla – Komplikácia

SELECT random() AS x, random() * 2 AS y

x y
0.926946882158518 0.789256273768842
Náhodné čísla

Náhodné čísla – Komplikácia

SELECT x, x * 2 as y
FROM (SELECT random() AS x) AS tmp

x y
0.239173104055226 0.478346208110452
Náhodné čísla

Náhodné čísla – Riadky v náhodnom poradí

SELECT * FROM názov_tabuľky

I ak nepožijeme ORDER BY nemáme garantované poradie riadkov,


I riadky ale nie sú v náhodnom poradí,
I je dané tým ako sú uložené na disku a stavom dátových štruktúr v
databázovom systéme,
I ak spustíme po sebe 2x ten istý dopyt bez toho, aby sme medzi tým
spravili niečo iné, pravdepodobne dostaneme riadky v tom istom poradí
Náhodné čísla Riadky v náhodnom poradí

Náhodné čísla – Riadky v náhodnom poradí

SELECT * FROM názov_tabuľky ORDER BY random()


Generovanie dát

Section 30

Generovanie dát
Generovanie dát

Generovanie jedneho riadku

SELECT
CASE floor(random() * 4)
WHEN 0 THEN ’Mária’ WHEN 1 THEN ’Katarína’
WHEN 2 THEN ’Júlia’ WHEN 3 THEN ’Eliška’
END AS name,
CASE floor(random() * 6)
WHEN 0 THEN ’Priezvisko 1’ WHEN 1 THEN ’Priezvisko 2’
WHEN 2 THEN ’Priezvisko 3’ WHEN 3 THEN ’Priezvisko 4’
WHEN 4 THEN ’Priezvisko 5’ WHEN 5 THEN ’Priezvisko 6’
END AS surname,
floor(random() * 70) + 13 AS age

name surname age


Júlia Priezvisko 5 33
Generovanie dát

Funkcia generate_series

generate_series(začiatok, koniec)

I generuje postupnosť celých čísel od začiatku po koniec s krokom jedna


I vracia tabuľku s jedným stĺpcom a potenciálne veľa riadkami
Generovanie dát

Funkcia generate_series

SELECT * FROM generate_series(-1, 2)

generate_series
-1
0
1
2
Generovanie dát

Funkcia generate_series

SELECT seq.i FROM generate_series(-1, 2) AS seq(i)

i
-1
0
1
2
Generovanie dát

Generovanie viacerých riadkov


SELECT
CASE floor(random() * 4)
WHEN 0 THEN ’Mária’ WHEN 1 THEN ’Katarína’
WHEN 2 THEN ’Júlia’ WHEN 3 THEN ’Eliška’
END AS name,
CASE floor(random() * 6)
WHEN 0 THEN ’Priezvisko 1’ WHEN 1 THEN ’Priezvisko 2’
WHEN 2 THEN ’Priezvisko 3’ WHEN 3 THEN ’Priezvisko 4’
WHEN 4 THEN ’Priezvisko 5’ WHEN 5 THEN ’Priezvisko 6’
END AS surname,
floor(random() * 70) + 13 AS age
FROM generate_series(1,20)
name surname age
Júlia Priezvisko 5 60
Katarína Priezvisko 3 50
... ... ...
Generovanie dát

CREATE TABLE AS

CREATE TABLE názov_tabuľky


[(názov_stĺpca_1, ... názov_stĺpca_n)]
AS
dopyt

I vytvorí zadanú tabuľky a naplní ju dátami z dopytu


I názvy stĺpcov sa odvodia z dopytu
I ak názvy stĺpcov zadáme explicitne, prebijú tie z dopytu
I typ stĺpcov sa odvodí z dopytu – nevieme ho zadať explicitne
I tento príkaz neakceptuje integritné obmedzenia
Generovanie dát

CREATE TABLE AS

CREATE TABLE users


AS
SELECT
id,
CASE floor(random() * 4)
WHEN 0 THEN ’Mária’ WHEN 1 THEN ’Katarína’
WHEN 2 THEN ’Júlia’ WHEN 3 THEN ’Eliška’
END AS name,
CASE floor(random() * 6)
WHEN 0 THEN ’Priezvisko 1’ WHEN 1 THEN ’Priezvisko 2’
WHEN 2 THEN ’Priezvisko 3’ WHEN 3 THEN ’Priezvisko 4’
WHEN 4 THEN ’Priezvisko 5’ WHEN 5 THEN ’Priezvisko 6’
END AS surname,
floor(random() * 70) + 13 AS age
FROM generate_series(1,20) AS seq(id)
Generovanie dát

INSERT INTO

INSERT INTO názov_tabuľky


(názov_stĺpca_1, ... názov_stĺpca_n)
dopyt

I namiesto VALUES môžeme uviesť dopyt


I do zadanej tabuľky vloží dátai z dopytu
Generovanie dát

INSERT INTO
Predpokladáme, že tabuľku už máme

INSERT INTO users (id, name, surname, age)


SELECT
id,
CASE floor(random() * 4)
WHEN 0 THEN ’Mária’ WHEN 1 THEN ’Katarína’
WHEN 2 THEN ’Júlia’ WHEN 3 THEN ’Eliška’
END AS name,
CASE floor(random() * 6)
WHEN 0 THEN ’Priezvisko 1’ WHEN 1 THEN ’Priezvisko 2’
WHEN 2 THEN ’Priezvisko 3’ WHEN 3 THEN ’Priezvisko 4’
WHEN 4 THEN ’Priezvisko 5’ WHEN 5 THEN ’Priezvisko 6’
END AS surname,
floor(random() * 70) + 13 AS age
FROM generate_series(1,20) AS seq(id)
Generovanie dát

Ďalší príklad

CREATE TABLE films


AS
SELECT
id,
’Film ’ || id AS name,
floor(random() * 45) + 1970 AS year
FROM generate_series(1,20) AS seq(id)
Generovanie dát

Generovanie väzobnej tabuľky – Ak idečka sú spojité

CREATE TABLE ratings


AS
SELECT
floor(random() * 10000 + 1) AS user_id,
floor(random() * 200 + 1) AS film_id,
floor(random() * 10 + 1) AS rating
FROM generate_series(1, 100)
Generovanie dát

Generovanie väzobnej tabuľky – Ak v idečkách sú medzery

CREATE TABLE ratings


AS
SELECT
user.id AS user_id,
film.id AS film_id,
floor(random() * 10 + 1) AS rating
FROM users
CROSS JOIN films
WHERE random() < 0.7
Pozor: toto je neefektívne pre veľké tabuľky
Generovanie dát

Generovanie maximálneho počtu prvkov

Pre každého používateľa chceme maximálne 2 obľúbené filmy

SELECT
users.id AS user_id,
tmp.id AS favourite_film_id
FROM
users
CROSS JOIN (SELECT
films.id
FROM films
ORDER BY random()
LIMIT 2) AS tmp
Generovanie dát

Generovanie maximálneho počtu prvkov

Pre každého používateľa chceme maximálne 2 obľúbené filmy

SELECT
users.id AS user_id,
tmp.id AS favourite_film_id
FROM
users
CROSS JOIN (SELECT
films.id
FROM films
ORDER BY random()
LIMIT 2) AS tmp
Nie tak úplne
Generovanie dát

Čo očakávame?

user_id favourite_film_id
1 3
1 7
2 61
2 1
3 76
3 6
... ...
Generovanie dát

Čo dostaneme?

user_id favourite_film_id
1 3
1 7
2 3
2 7
3 3
3 7
... ...
Generovanie dát

Prečo?

SELECT
users.id AS user_id,
tmp.id AS favourite_film_id
FROM
users
CROSS JOIN (SELECT
films.id
FROM films
ORDER BY random()
LIMIT 2) AS tmp
Generovanie dát

Prečo?

SELECT
users.id AS user_id,
tmp.id AS favourite_film_id
FROM
users
CROSS JOIN [(2), (7)] as tmp

[(2), (7)] má predstavovať akože tabuľku s dvoma riadkami


I toto je iba moja vizualizácia, nič také sa nedá zapísať
Generovanie dát

A ako to opraviť?

Pomocou vlastnej databázovej funkcie


Generovanie dát

A ako to opraviť?
CREATE FUNCTION random_films(x int) RETURNS TABLE (id integer)
LANGUAGE SQL AS
$$
SELECT id FROM films ORDER BY random() LIMIT 2
$$

SELECT
user.id AS user_id,
tmp.id AS favourite_film_id
FROM
users
CROSS JOIN LATERAL random_films(users.id) AS tmp
I volanie funkcie sa odkazuje na riadok tabuľky, takže sa musí zavolať
pre každý riadok
I volanie vlastnej databázovej funkcie systém štandarne nezoptimalizuje
a každé volanie vyhodnotí nanovo
Generovanie dát

Kontrola rozloženia pravdepodobnosti

SELECT round(random() * 10) AS x,


round(count(*) * 100.0 / 1000000.0, 2) AS prob
FROM generate_series(1, 1000000) GROUP BY x ORDER BY x

x prob
0 5.03
1 10.02
2 9.99
3 10.01
4 10.01
5 10.00
6 9.93
7 9.99
8 10.04
9 9.97
10 5.00
Aktualizovanie štruktúry databázy

Section 31

Aktualizovanie štruktúry databázy


Aktualizovanie štruktúry databázy

Aktualizácia štruktúry databázy

Štruktúra databázy sa vyvíja


Aktualizovanie štruktúry databázy

Aktualizácia štruktúry databázy

Čo s produkciou?
Aktualizovanie štruktúry databázy

Aktualizácia štruktúry databázy

ALTER TABLE
Aktualizovanie štruktúry databázy

Premenovanie tabuľky

ALTER TABLE názov_tabuľky


RENAME TO nový_názov
Aktualizovanie štruktúry databázy

Pridanie nového stĺpca

ALTER TABLE názov_tabuľky


ADD [COLUMN] definícia_stĺpca

definícia_stĺpca ako pri CREATE TABLE


Aktualizovanie štruktúry databázy

Pridanie nového stĺpca – Čo existujúce riadky?

DEFAULT hodnota

NULL
Aktualizovanie štruktúry databázy

Pridanie nového stĺpca – Integritné obmedzenia

Pozor!!!

Existujúce riadky nemusia spĺňať integritné obmedzenia!


Aktualizovanie štruktúry databázy

Pridanie nového stĺpca – Integritné obmedzenia

ALTER TABLE films


ADD COLUMN length integer NOT NULL

Ak tabuľka neobsahuje riadky, potom všetko zbehne

Ak tabuľka obsahuje nejaké riadky, potom dostaneme chybu


ERROR: column "length" contains null values
Aktualizovanie štruktúry databázy

Zmazanie existujúceho stĺpca

ALTER TABLE názov_tabuľky


DROP [COLUMN] názov_stĺpca [CASCADE]

CASCASE – zmaže aj odkazujúce sa objekty


Aktualizovanie štruktúry databázy

Premenovanie existujúceho stĺpca

ALTER TABLE názov_tabuľky


RENAME [COLUMN] názov_stĺpca TO nový_názov
Aktualizovanie štruktúry databázy

Nastavenie novej DEFAULT hodnoty

ALTER TABLE názov_tabuľky


ALTER [COLUMN] názov_stĺpca SET DEFAULT výraz

neberie ohľad na predchádzajúcu DEFAULT hodnotu


Aktualizovanie štruktúry databázy

Zrušenie DEFAULT hodnoty

ALTER TABLE názov_tabuľky


ALTER [COLUMN] názov_stĺpca DROP DEFAULT
Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

ALTER TABLE názov_tabuľky


ALTER [COLUMN] názov_stĺpca [SET DATA] TYPE názov_typu
Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

Čo s dátami?
Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

Automatická konverzia dát

integer → varchar
varchar(2) → varchar(255)
... → ...
Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

Konvertuje sa aj DEFAULT hodnota


Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

vals
key : varchar value : varchar
length 20
height 67

ALTER TABLE vals


ALTER COLUMN value SET DATA TYPE integer

ERROR: column "value" cannot be cast automatically


to type integer
Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

ALTER TABLE názov_tabuľky


ALTER [COLUMN] názov_stĺpca
[SET DATA] TYPE názov_typu [USING nová_hodnota]
Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

vals
key : varchar value : varchar
length 20
height 67

ALTER TABLE vals


ALTER COLUMN value
SET DATA TYPE integer USING value::integer

vals
key : varchar value : integer
length 20
height 67
Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

users
id : serial name : varchar
1 johny
2 oz

ALTER TABLE users


ALTER COLUMN name SET DATA TYPE varchar(2)

ERROR: value too long for type character varying(2)


Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

users
id : serial name : varchar
1 johny
2 oz

ALTER TABLE users


ALTER COLUMN name
SET DATA TYPE varchar(2) USING left(name, 2)

users
id : serial name : varchar(2)
1 jo
2 oz
Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

users
id : serial name : varchar tel_number : integer
1 johny 9393344
2 oz 943423

ALTER TABLE users


ALTER COLUMN tel_number
SET DATA TYPE varchar USING concat(’+466’, tel_number)

users
id : serial name : varchar tel_number : varchar
1 johny +4669393344
2 oz +466943423
Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

USING sa môže odkazovať aj na iné stĺpce


Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

A čo DEFAULT hodnota?
Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

Tá sa použitím USING nekonvertuje


Aktualizovanie štruktúry databázy

Zmena dátového typu stĺpca

ALTER TABLE users


ALTER COLUMN tel_number
DROP DEFAULT;

ALTER TABLE users


ALTER COLUMN tel_number
SET DATA TYPE varchar USING concat(’+466’, tel_number);

ALTER TABLE users


ALTER COLUMN tel_number
SET DEFAULT ’+88083582’;
Aktualizovanie štruktúry databázy

Pridanie integritného obmedzenia NOT NULL

ALTER TABLE názov_tabuľky


ALTER [ COLUMN ] názov_stĺpca SET NOT NULL
Aktualizovanie štruktúry databázy

Pridanie integritného obmedzenia NOT NULL

NULL hodnoty v existujúcich riadkoch vedú na chybu

integritné obmedzenie sa nevytvorí


Aktualizovanie štruktúry databázy

Odstránenie integritného obmedzenia NOT NULL

ALTER TABLE názov_tabuľky


ALTER [ COLUMN ] názov_stĺpca DROP NOT NULL
Aktualizovanie štruktúry databázy

Pridanie ostatných integritných obmedzení

ALTER TABLE názov_tabuľky


ADD definícia_integritného_obmedzenia

kde definícia_integritného_obmedzenia je
[CONSTRAINT názov] UNIQUE (...)
[CONSTRAINT názov] CHECK (...)
[CONSTRAINT názov] PRIMARY KEY (...)
[CONSTRAINT názov] FOREIGN KEY (...) REFERENCES ...
Aktualizovanie štruktúry databázy

Pridanie ostatných integritných obmedzení

Ak dáta porušujú integritné obmedzenie, tak nie je pridané


Aktualizovanie štruktúry databázy

Premenovanie existujúceho integritného obmedzenia

ALTER TABLE názov_tabuľky


RENAME CONSTRAINT názov_obmedzenia TO nový_názov
Aktualizovanie štruktúry databázy

Odstránenie existujúceho integritného obmedzenia

ALTER TABLE názov_obmedzenia


DROP CONSTRAINT názov_obmedzenia
Aktualizovanie štruktúry databázy

ALTER script

I postupnosť poväčšine ALTER príkazov, ktoré docielia požadovanú


zmenu štruktúry databázy
Aktualizovanie štruktúry databázy

Komplexný príklad

films
id : serial
name : varchar
director : varchar
price : numeric

chceme zmeniť na

films
persons
id : serial
name : varchar id : serial
director_id : integer name : varchar
price : numeric
Aktualizovanie štruktúry databázy

Komplexný príklad

CREATE TABLE persons


(
id serial,
name varchar
);

INSERT INTO persons (name)


SELECT DISTINCT director
FROM films;
Aktualizovanie štruktúry databázy

Komplexný príklad

ALTER TABLE films


ALTER COLUMN director
SET DATA TYPE integer USING (SELECT id
FROM persons
WHERE name = director);
Aktualizovanie štruktúry databázy

Komplexný príklad

Toto žiaľ neide. USING nepodporuje vnorené SELECTy.


Aktualizovanie štruktúry databázy

Komplexný príklad

ALTER TABLE films


ADD COLUMN director_id integer;

UPDATE films AS f SET


director_id = (SELECT p.id
FROM persons AS p
WHERE p.name = f.director);
Aktualizovanie štruktúry databázy

Komplexný príklad

ALTER TABLE films


DROP COLUMN director;
Skúška

Section 32

Skúška
Skúška

Skúška

I na papier
I podobne ako písomka
I 50 bodov
I termíny sú v aise

aby som zistil, či látke naozaj rozumiete, môže sa stať, že:


I budú typy úloh, ktoré sme na cviku neriešili
I veci, ktoré sme brali oddelene, bude treba skombinovať
I budem sa pýtať na okrajové prípady
Čo bude na DB2?

Section 33

Čo bude na DB2?
Čo bude na DB2?

Predbežný obsah

Použitie relačnej DB a SQL v projekte


I JDBC (Java Database Connectivity)
I Row Data Gateway, Transaction Script, Active Record
I Transakcie
I Zamykanie dát

Optimalizácia SQL kódu


I Indexy
I Partície
I Rekurzívne dopyty
I Serverové programovanie
I spúšťače, (materializované) pohľady
Čo bude na DB2?

Predbežný obsah

Objektovo orientovaný prístup k relačnej DB


I Domain Model, Data Mapper
I JPA (Java Persistence API)
Čo bude na DB2?

Koniec

Koniec

You might also like