Aplikační a programové vybavení

Slides:



Advertisements
Podobné prezentace
KIV/ZIS Cvičení 6 SQL - SELECT.
Advertisements

MS ACCESS - DOTAZY DATABÁZOVÉ SYSTÉMY.
SQL Další dotazy a pohledy
Cvičení 06 Ing. Pavel Bednář
Základy jazyka SQL Jan Tichava
SQL: DDL v ORACLE CREATE TABLE jméno_tabulky (atribut datový_typ [DEFAULT][attribut_constraint] [, atribut datový_typ [DEFAULT] [attribut_constraint]],...
Aplikační a programové vybavení
Jazyk SQL Ing. Zdena DOBEŠOVÁ. SQL Structured Query Language 1974 SEQUEL (Structured English Query Language) neprocedurální relační dotazovací jazyk norma.
DB1 – 9. cvičení Optimalizace dotazu Konkurenční přístup a deadlock Indexace Transakce.
Databázové systémy SQL Výběr dat.
YDASYS1 Ing. Monika Šimková.
Fakulta elektrotechniky a informatiky
Cvičení 03 SQL Select Ing. Pavel Bednář
Informační systémy Nástroje pro sběr dat, návrh a realizace databáze.
AGREGACE Distinct, Group By, Having, SUM, …. DISTINCT  Slučování stejných řádků ve výsledku dotazu. AGREGACE 2 JménoPříjmeníID FrantišekVomáčka1 JosefPokorný2.
Další dotazy SQL Structured Query Language. Některé SQL příkazy mohou mít v sobě obsaženy další kompletní příkazy SELECT. Využijeme je tam, kde potřebujeme.
SQL Structured Query Language
Informatika pro ekonomy II přednáška 11
Databázové systémy 1 Cvičení č. 6 Fakulta elektrotechniky a informatiky Univerzita Pardubice.
Databázové systémy 1 Cvičení č. 4 Fakulta elektrotechniky a informatiky Univerzita Pardubice.
Databázové systémy 1 Cvičení č. 2 Fakulta elektrotechniky a informatiky Univerzita Pardubice.
Databázové systémy I Přednáška č. 5 RNDr. David Žák, Ph.D. Fakulta elektrotechniky a informatiky
Databázové systémy 2 Cvičení č. 6 Ing. Tomáš Váňa Fakulta elektrotechniky a informatiky Univerzita Pardubice.
Databázové systémy 1 Cvičení č. 3 Fakulta elektrotechniky a informatiky Univerzita Pardubice.
Temporální databáze a TSQL
SQL Přednáška DB1. Literatura CONNOLLY, T.M.-BEGG,C.E.-STRACHAN,A.D.: Database Systems – A Practial Approach to Design, Implementation and Management.
MySQL - Vytvoření nové tabulky  create table jméno_tabulky (jméno_položky typ_položky,... ) Přehled nejběžnějších datových typů Přehled nejběžnějších.
Databázové systémy II Přednáška č. 8 – Pohledy (Views)
Školení správců II. Petr Pinkas RNDr. Vít Ochozka.
Fakulta elektrotechniky a informatiky
Databázové systémy I Cvičení č. 9 Fakulta elektrotechniky a informatiky Univerzita Pardubice 2013.
KIV/ZIS cvičení 6 Tomáš Potužák. Pokračování SQL Klauzule GROUP BY a dotazy nad více tabulkami Stáhnout soubor studenti_dotazy_sql.mdb.
Databázové systémy I Cvičení č. 6 Fakulta elektrotechniky a informatiky Univerzita Pardubice 2013.
Databázové systémy Přednáška č. 6.
SQL – základní pojmy Ing. Roman Danel, Ph.D.
SQL PVA Jan Hora. SQL „graficky“ Grafický vs. pravý SQL SELECT ORDED BY WHERE.
Rauer Luboš Kopic Petr Blažek Tomáš. Structured Query Language - dotazovací jazyk -> pracuje s dotazy - neprocedurální jazyk - mocný, ale přitom jednoduchý.
Databázové systémy 2 Cvičení č. 6 Ing. Tomáš Váňa Fakulta elektrotechniky a informatiky Univerzita Pardubice.
Fakulta elektrotechniky a informatiky
Číslo šablony: III/2 VY_32_INOVACE_P4_3.8 Tematická oblast: Aplikační software pro práci s informacemi II. Databáze – základy SQL Typ: DUM - kombinovaný.
Databázové systémy I Cvičení č. 7 Fakulta elektrotechniky a informatiky Univerzita Pardubice 2013.
Informatika II PAA DOTAZOVACÍ JAZYKY
Aplikační a programové vybavení
Databáze velké množství dat pevně dané struktury
Obchodní akademie, Ostrava-Poruba, příspěvková organizace Vzdělávací materiál/DUM VY_32_INOVACE_01B13 Autor Ing. Jiří Kalousek Období vytvoření březen.
Základní obeznámení s jazykem SQL Databázové systémy.
Databázové systémy SQL Výběr dat.
 Agregační funkce  Agregační funkce jsou to funkce, které nějakým způsobem zpracují více hodnot a jako výsledek vrátí hodnotu jednu COUNT()  Funkce.
Použití dotazu jako zdroj dat pro pohled Vypracovala: Procházková Petra.
Aplikační a programové vybavení
SQL Další dotazy a pohledy Databázové systémy. Některé SQL příkazy mohou mít v sobě obsaženy další kompletní příkazy SELECT. Využijeme je tam, kde potřebujeme.
Teorie zpracování dat RELAČNÍ DATOVÝ MODEL.
ACCESS DOTAZY Ing. Jana Horáková IKT MS Office
SQL Structured Query Language
Databázové systémy I Přednáška č. 6 RNDr. David Žák, Ph.D. Fakulta elektrotechniky a informatiky
Příkazy jazyka SQL ve VFP a na SQL Serveru
Databáze MS ACCESS 2010.
SQL – příkaz SELECT Ing. Roman Danel, Ph.D.
Databázové systémy I Přednáška 5 Databázové systémy 1 – KIT/IDAS1
Databázové systémy I Přednáška 8 Databázové systémy 1 – KIT/IDAS1
Ing. Tomáš Váňa, Ing. Jiří Zechmeister
Dotazovací jazyk SQL I.
Databázové systémy a SQL
Databázové systémy a SQL
Optimalizace SQL dotazů
Počítačová cvičení z předmětu Datové sklady
Dotazovací jazyk SQL - II
Přednáška 7 SQL – JOIN.
Přednáška 9 Triggery.
Databázové systémy a SQL
Transkript prezentace:

Aplikační a programové vybavení Databáze – jazyk SQL

Krok 1: vytvoření databáze příkaz CREATE Syntaxe je poměrně složitá a v mnoha ohledech velmi závisí na konkrétním databázovém systému. Viz. příslušný manuál oblíbeného databázového systému.

Krok 1: vytvoření databáze

Krok 1: vytvoření databáze osoby id_osoby prezdivka jmeno prijmeni datum_narozeni id_aadresy kontakty id_kontakty id_osoby id_typy_kontaktu kontakt vztahy id_vztahy id_osoby1 id_osoby2 poznamka id_typy_vztahu schuzky typy_vztahu id_schuzky datum misto poznamka id_typy_vztahu nazev osoby_schuzky typy_kontaktu id_osoby id_schuzky id_typy_kontaktu nazev

Krok 2: naplnění databáze příkaz INSERT logika: INSERT kam VALUES co INSERT INTO tabulka (seznam_sloupců) VALUES (seznam_hodnot) INSERT [ IGNORE ] [ INTO ] tabulka [ ( sloupec1, sloupec2, … ) ] VALUES ( { výraz1 | DEFAULT | NULL }, … ) INSERT INTO osoby (jmeno, prijmeni) VALUES (‘Chlastislav’, ‘Peruňka’); Pořadí sloupců musí být stejné jako pořadí hodnot v seznamu hodnot (tedy musí být stejný počet položek v obou seznamech). Pořadí sloupců v INSERT dotazu nemusí vůbec odpovídat pořadí sloupců v definici tabulky. Je vhodné přednostně používat jednoduché uvozovky pro řetězce, je to přenositelnější (neboli dvojité uvozovky mohou a nemusí fungovat, záleží na DB serveru). Klíčové slovo INTO nemá vůbec žádný význam, jeho cílem je jen zlepšovat čitelnost SQL dotazu (INSERT INTO = vlož do)

Krok 2: naplnění databáze Nemusí se vkládat všechny hodnoty INSERT INTO osoby (jmeno, prijmeni, prezdivka, datum_narozeni, id_adresy); VALUES ('Chlastislav', 'Peruňka', 'Chlastík', NULL, DEFAULT); Velmi zkrácený zápis: INSERT osoby VALUES ('Chlastislav', 'Sosna', 'Chlastík'); Vložení data (PgSQL): INSERT INTO osoby (jmeno, prijmeni, prezdivka, datum_narozeni) VALUES ('Chlastislav', 'Sosna', 'Chlastík', TO_TIMESTAMP('5.1.1984', 'DD.MM.YYYY'), ); Vložení data (MySQL): INSERT INTO osoby( jmeno, prijmeni, prezdivka, datum_narozeni) VALUES ('Chlastislav', 'Sosna', 'Chlastík' STR_TO_DATE('5.1.1984', '%d.%m.%Y' ), ); Velmi zkrácený zápis se nedoporučuje používat, protože je poněkud nejednoznačný, závisí na pořadí sloupců v definici tabulky a to obecně vzato nemusí být zajištěno. Pokud jsou sloupce uvedeny, tak je SQL dotaz odolný proti změnám struktury DB (buď funguje pořád stejně nebo nefunguje vůbec)

Krok 2: naplnění databáze Pravidla vkládání dat nevkládá se hodnota automaticky generovaného klíče: auto_increment (MySQL), serial (PgSQL) výjimkou je hromadný import dat do více tabulek pokud to definice sloupce (vlastnost NULL) umožňuje není nutné hodnotu vkládat neuvedení sloupce má stejný efekt jako uvedení DEFAULT (vloží se výchozí hodnota z definice sloupce) uvedení hodnoty NULL nevloží žádnou hodnotu) datum se musí vkládat ve formátu DB serveru nebo se do něj musí převést formátovací funkce se liší pro různé DB servery

Krok 3: aktualizace databáze příkaz UPDATE logika: UPDATE kde SET jak WHERE co UPDATE tabulka SET seznam_modifikací WHERE vyhledávací_podmínka UPDATE tabulka SET sloupec1 = hodnota1 [,sloupec2 = hodnota2 ...] [ WHERE vyhledávací_podmínka ] UPDATE osoby SET vyska = '196' WHERE id_osoby=42; Kde = v jaké tabulce aktualizovat Jak = konkrétní změny, které se mají provést Co = které řádky aktualizovat Vyhledávací podmínka je výraz, který se vyhodnotí pro každý záznam v tabulce jako TRUE nebo FALSE.

Krok 3: aktualizace databáze Pokud není uvedená podmínka WHERE, aktualizují se všechny záznamy v tabulce UPDATE osoby SET datum_narozeni=NULL; V podmínce se nejčastěji používá klíč: UPDATE osoby SET prezdivka = 'Chlastík' WHERE id=42 UPDATE osoby SET prezdivka = 'Chlastík' WHERE jmeno='Chlastislav' AND prijmeni='Peruňka' AND prezdivka='Chlastik'; pokud je klíč složený, musí se uvádět všechny složky Podmínka WHERE je sice nepovinná, ale nejčastěji se aktualizace aplikuje s podmínkou WHERE, která obsahuje konkrétní hodnotu klíče, neboli nejčastěji se aktualizuje jeden záznam v tabulce. Hromadné aktualizace jsou sice možné, ale poměrně vzácné. Z toho vyplývá obrovská výhoda umělých (dumb) klíčů – zjednodušují práci s aktualizačními dotazy, protože u složených klíčů se neustále musí uvádět všechny složky klíče (složený klíč identifikuje každou kombinaci složek jako unikátní). Proto se tedy v tabulkách obvykle používají alespoň dva klíče – jeden je jednoduchý a umělý pro vnitřní potřebu aplikace, druhý je obvykle složený (vychází z reality) a je pro potřebu uživatele.

Krok 4: získání dat z databáze příkaz SELECT logika: SELECT co FROM odkud WHERE jak co – jaká data chceme, nejčastěji jaké sloupce odkud – zdroj dat, nejčastěji tabulka nebo kombinace tabulek jak – jakým způsobem data získat, tedy jaké podmínky pro požadovaná data platí příkaz SELECT je nejpoužívanější a také nejsložitější příkaz jazyka SQL Důležité je že SELECT umí z databáze získat data v původním DB schématu (před normalizací), spojování tabulek tedy velmi těsně souvisí právě s normalizací a s definicí cizích klíčů. Co = jaká data, neboli jaké sloupce Odkud = zdroj dat – tabulky, pohledy, poddotazy Jak = jakým způsobem vybrat data, podmínky které musí být splněné

SELECT – struktura příkazu SELECT [ ALL | DISTINCT ] výběrový_výraz1, výběrový_výraz2, … [ FROM odkazy_na_tabulky [ WHERE vyhledávací_podmínka ] [ GROUP BY { jméno_sloupce | výraz } [ ASC | DESC ], … ] [ HAVING vyhledávací_podmínka ] [ ORDER BY { jméno_sloupce | výraz } ] Toto je základní struktura příkazu SELECT, po rozvinutí zástupných symbolů a po zahrnutí méně používaných klauzulí by syntaxe příkazu SELECT vydala na několik stran A4.

SELECT – příklad nejjednodušší struktura: SELECT seznam_sloupců FROM tabulka [ WHERE podmínka ] SELECT id_osoby, jmeno, prijmeni FROM osoby WHERE vyska > 190 Co (operace projekce): hodnoty ve sloupcích jmeno a prijmeni Odkud: z tabulky osoby Jak (operace selekce): všechny osoby vyšší než 190 cm Nejjednodušší SELECT je z jedné tabulky, nicméně prakticky to není příliš časté.

SELECT – struktura příkazu SELECT [ ALL | DISTINCT ] výběrový_výraz1, výběrový_výraz2, … [ FROM odkazy_na_tabulky [ WHERE vyhledávací_podmínka ] [ GROUP BY { jméno_sloupce | výraz } [ ASC | DESC ], … ] [ HAVING vyhledávací_podmínka ] [ ORDER BY { jméno_sloupce | výraz } ]

SELECT – výběrový výraz SELECT [ ALL | DISTINCT ] { * | tabulka.* | [tabulka.]sloupec1 [AS alias1] [,tabulka.]sloupec2 [ AS alias2] [,…] } FROM … * – vybere všechny sloupce, které se objeví v části FROM tabulka.* – vybere všechny sloupce zadané tabulky tabulka.sloupec – vybere sloupec ze zadané tabulky AS – přiřadí dočasně sloupci jiný název (alias) – Název tabulky je vhodné psát vždy když se v části FROM vyskytuje více tabulek. A to i tehdy pokud to není vysloveně nutné (tabulky nemají shodné sloupce). Pokud jsou totiž názvy tabulek uvedeny, tak je SQL dotaz odolný vůči změnám v DB, tedy pokud se přidá do nějaké tabulky sloupec, jehož název je náhodou stejný jako název sloupce v jiné tabulce, pak výsledek SQL dotazu nezmění. Pokud by však názvy tabulek nebyly uvedeny, mohlo by se stát, že najednou začne vracet obsah jiné tabulky (té, ve které byl vytvořen nový sloupec).

SELECT – výběrový výraz Varianty téhož dotazu: SELECT schuzky.id_schuzky, schuzky.datum, schuzky.misto, schuzky.poznamka FROM schuzky; SELECT id_schuzky, datum, misto, poznamka FROM schuzky; SELECT schuzky.* FROM schuzky; SELECT * FROM schuzky; Výběr všech míst na kterých se koná nějaká schůzka: SELECT misto FROM schuzky; SELECT ALL misto FROM schuzky; Bez duplicitních řádků (tabulka × relace) SELECT DISTINCT misto FROM schuzky; – Obecně je opět výhodnější vybírat jen ty sloupce, které jsou v aplikaci potřeba a vyhnout se používání *. V případě SELECTu sice nemůže dojít k funkčním problémům, ale může dojít k výkonovým problémům. Pokud by se například do tabulky osob přidalo pole s fotkou osoby, tak by každý dotaz, který pracuje s osobami a který používá * místo seznamu sloupců z databáze přenesl (zbytečně) několik MB fotek. Výsledek dotazu, který vybere všechna místa na kterých se koná nějaká schůzka je tabulka, ale není relace. Protože definice relace říká, že relace je množina tak to znamená, že relace nesmí obsahovat stejné prvky. Výsledek dotazu 'SELECT misto FROM schuzky;' by tedy nemělo být možné uložit do databáze (nelze z něj vytvořit relaci), je však možné z něj vytvořit pohled. Naproti tomu výsledkem posledního dotazu je relace, protože neobsahuje duplicitní řádky. Klíčové slovo ALL znamená, že do řádku jsou zahrnuty i duplicity, což je výchozí stav, není tedy nutné jej uvádět. Smysl to může mít v rámci dokumentace kódu pro zdůraznění toho, že zpracování aplikace trvá na tom, aby ve výsledku duplicity byly.

http://kantorek.webzdarma.cz/

SELECT – struktura příkazu SELECT [ ALL | DISTINCT ] výběrový_výraz1, výběrový_výraz2, … [ FROM odkazy_na_tabulky [ WHERE vyhledávací_podmínka ] [ GROUP BY { jméno_sloupce | výraz } [ ASC | DESC ], … ] [ HAVING vyhledávací_podmínka ] [ ORDER BY { jméno_sloupce | výraz } ]

SELECT – odkazy na tabulky Výběr dat z jedné tabulky není příliš užitečný. Data je možné získat současně z více tabulek jejich spojením. Spojením tabulek (Θ - join) dochází k rekonstrukci původního schématu DB. Tabulkou může být: relace (skutečná tabulka ve schématu) pohled (virtuální tabulka ve schématu) výsledek dotazu (virtuální tabulka) (rekurze) výsledek spojení tabulek (virtuální tabulka) Pro spojování tabulek je obecně možné použít dva přístupy (nebo jejich kombinaci) jednak je to operátor JOIN a jednak je to vnořený dotaz. Vnořený dotaz (poddotaz) je možné používat protože výsledkem dotazu je tabulka a v části FROM v SELECT dotazu se očekává také tabulka. Definice struktury SELECTu tedy je rekurzivní a rekurzi dobře podporuje.

SELECT – JOIN … FROM tabulka1 [AS alias1] [ [ LEFT | RIGHT | INNER | NATURAL ] JOIN tabulka2 [AS alias1] [ ON spojovací_podmínka ] ] [ WHERE … Na levé i pravé straně operátoru JOIN je tabulka Pro spojení je nutné zadat spojovací podmínku, která platí pro všechny řádky výsledné tabulky Pro NATURAL JOIN (přirozené spojení) je spojovací podmínka automatická – rovnost hodnot ve stejně pojmenovaných sloupcích Kartézský součin (všechny kombinace): SELECT * FROM osoby, kontakty; Spojovací podmínka je výraz, který se vyhodnotí jako TRUE nebo FALSE pro každý řádek tabulky.

SELECT – JOIN SELECT * FROM osoby INNER JOIN kontakty ON osoby.id_osoby = kontakty.id_osoby; Vybere z obou tabulek takové kombinace záznamů pro které platí podmínka (1:1 nebo 1:1..N). Vybere všechny osoby, které mají nějaký kontakt, každá osoba je uvedena tolikrát kolik má kontaktů. SELECT * FROM osoby NATURAL JOIN kontakty; Vybere všechny záznamy ve kterých se rovná hodnota stejně pojmenovaných sloupců. JOIN, INNER JOIN, NATURAL JOIN je symetrický Klíčové slovo INNER je zbytečné, protože výchozí stav je INNER, znamená to, že to není ani LEFT, ani RIGHT.

SELECT – JOIN SELECT * FROM osoby LEFT JOIN kontakty ON osoby.id_osoby = kontakty.id_osoby; Vybere z levé tabulky vše a z pravé všechny záznamy, pro které platí podmínka (1:0..1 nebo 1:0..N) Vybere všechny osoby a pokud má osoba kontakty, tak vypíše i kontakty (1:0..1 nebo 1:0..N) SELECT * FROM osoby RIGHT JOIN kontakty ON osoby.id_osoby = kontakty.id_osoby; Vybere z pravé tabulky vše a z levé záznamy, pro které platí podmínka. Vybere všechny kontakty a ke každému vypíše osoby (v tomto konkrétním případě je stejné jako INNER JOIN). Stejné je to proto, že je v tabulce kontakty definované integritní omezení - cizí klíč na tabulku osoby sloupec id_osoby a sloupec kontakty.id_osoby je povinný (NOT NULL). Což znamená, že id_osoby v tabulce kontakty musí obsahovat hodnotu a tato hodnota musí být existující ID osoby v tabulce osoby. Tedy nemůže existovat kontakt, pro který by podmínka osoby.id_osoby=konktakty.id_osoby nebyla splněna, proto osoby RIGHT JOIN kontakty v tomto případě dává stejný výsledek jako osoby INNER JOIN kontakty. Osoby LEFT JOIN kontakty dává jiný výsledek, protože může existovat osoba pro kterou výše uvedená podmínka splněná není (osoba nemá kontakt).

SELECT – JOIN SELECT * FROM vztahy LEFT JOIN typy_vztahu ON vztahy.id_typy_vztahu = typy_vztahu.id_typy_vztahu; Vybere všechny vztahy a ke každému přiřadí typ vztahu. Vypíše i vztahy, které nemají žádný typ (neměly by existovat). SELECT * FROM vztahy RIGHT JOIN typy_vztahu ON vztahy.id_typy_vztahu = typy_vztahu.id_typy_vztahu; Vybere všechny typy vztahů a ke každému přiřadí vztahy, které mají daný typ. Vypíše i typy vztahů, které nejsou použité. LEFT JOIN vybere z levé tabulky (z tabulky která je vlevo od slova JOIN) všechny záznamy a z druhé jen ty záznamy, pro které platí daná podmínka. RIGHT JOIN vybere z pravé tabulky vše a z levé jen ty pro které platí podmínka.

SELECT – JOIN Ekvivalentní dotazy: SELECT * FROM kontakty LEFT JOIN typy_kontaktu ON kontakty.id_typy_kontaktu = typy_kontaktu.id_typy_kontaktu; SELECT * FROM typy_kontaktu RIGHT JOIN kontakty ON kontakty.id_typy_kontaktu = typy_kontaktu.id_typy_kontaktu; SELECT * FROM kontakty INNER JOIN typy_kontaktu ON kontakty.id_typy_kontaktu = typy_kontaktu.id_typy_kontaktu; SELECT * FROM kontakty NATURAL JOIN typy_kontaktu; První dva dotazy jsou stejné, protože platí a LEFT JOIN b je totéž jako b RIGHT JOIN a Druhé dva dotazy jsou stejné protože INNER JOIN je totéž co JOIN (bez LEFT nebo RIGHT) a platí, že NATURAL JOIN je JOIN u kterého se automaticky jako spojovací podmínka předpokládá rovnost hodnot ve stejně pojmenovaných sloupcích z obou tabulek (čili kontakty.id_typy_kontaktu=typy_kontaktu.id_typy_kontaktu).

{ tabulka1 [AS alias1] | pod_dotaz [ AS alias2] } … FROM { tabulka1 [AS alias1] | pod_dotaz [ AS alias2] } [ [ LEFT | RIGHT | INNER | NATURAL ] JOIN tabulka2 [ ON tabulka_1.sloupec1 { > | >= | < | <= | = | <> } tabulka_2.sloupec2] ] [ WHERE … Nejčastěji se spojení používá k rekonstrukci původního schématu. Spojovací podmínka je tedy nejčastěji rovnost hodnot dvou sloupců, které zajišťují vazbu mezi relacemi. Spojovací podmínka může být i exotičtější, ale potom je obvykle výhodnější použít WHERE. Spojovat je možné tabulky – tedy relace i pohledy i výsledky jiných dotazů.

http://kantorek.webzdarma.cz/

SELECT – struktura příkazu SELECT [ ALL | DISTINCT ] výběrový_výraz1, výběrový_výraz2, … [ FROM odkazy_na_tabulky [ WHERE vyhledávací_podmínka ] [ GROUP BY { jméno_sloupce | výraz } [ ASC | DESC ], … ] [ HAVING vyhledávací_podmínka ] [ ORDER BY { jméno_sloupce | výraz } ]

SELECT – vyhledávací podmínka WHERE { výraz1 [NOT] { = | <> | < | <= | > | >= } výraz2 | { ALL | ANY | SOME } pod-dotaz | výraz [NOT] IN { množina_hodnot | pod-dotaz } | výraz [NOT] LIKE vzor | výraz [NOT] BETWEEN dolní_mez AND |horní_mez | výraz [NOT] EXISTS (pod-dotaz) } [ { AND | OR } …] Operátor LIKE slouží k porovnávání řetězců. Vzor je řetězec, který může obsahovat zástupné znaky: podtržítko (_) = jeden libovolný znak a procento (%) = libovolný počet znaků (včetně žádného znaku). Ostatní operátory umožňují jak práci s řetězci tak práci s čísly. Operátor BETWEEN zahrnuje meze do výběru. Řetězce se běžně porovnávají nezávisle na velikosti písmen, tedy 'P' = 'p'

SELECT – WHERE SELECT jmeno,prijmeni FROM osoby WHERE jmeno LIKE ‘P%’; SELECT jmeno,prijmeni FROM osoby WHERE (jmeno LIKE ‘P%’) OR (jmeno LIKE ‘L%’); SELECT jmeno,prijmeni FROM osoby WHERE jmeno LIKE ‘_etr’; SELECT jmeno,prijmeni FROM osoby WHERE jmeno IN ('Petr', 'Pavel'); SELECT jmeno,prijmeni FROM osoby WHERE jmeno BETWEEN 'Pavel' AND 'Petr'; Vybere všechny osoby, jejichž jméno začíná na P Vybere všechny osoby, jejichž jméno začíná na P nebo na L Vybere všechny osoby, jejichž jméno končí na 'etr' a má 4 znaky. Vybere všechny osoby, jejichž jméno je Petr nebo Pavel Vybere všechny osoby, jejichž jméno je mezi Pavel a Petr včetně.

SELECT – WHERE Osoby, které jsou vyšší než nejvyšší Petr: SELECT jmeno,prijmeni FROM osoby WHERE vyska >= ALL ( SELECT vyska FROM osoby jmeno = 'Petr' ); Seznam osob, které bydlí v Brně: SELECT osoby.jmeno, osoby.prijmeni, adresy.mesto FROM osoby JOIN adresy ON osoby.id_adresy = adresy.id_adresy WHERE mesto = 'Brno'; Vybere všechny osoby, pro které platí, že jejich výška je větší nebo rovna výšce každé osoby jménem Petr. Využívá vnořený dotaz v části WHERE, vnořený dotaz vypíše výšku všech osob jménem Petr. Na dotaz se lze dívat také tak, že pod-dotaz – „SELECT vyska FROM osoby WHERE jmeno ‘Petr’” vrátí několik záznamů (tolik, kolik je v databázi Petrů) např. 175, 183, 179, 190. Podmínka vyska >= ALL (175, 183, 179, 190) se je ekvivalentní zápisu: “vyska > 175 AND vyska > 183 AND vyska > 179 AND vyska > 190”. Klíčová slova ANY / SOME fungují obdobně, pouze se AND nahradí za OR. Mezi ANY a SOME není žádný rozdíl. Vypíše záznamy z tabulky, která vznikne spojením tabulky osob a adres (spojovací podmínka říká že se má na id_adresy v tabulce osob navázat odpovídající id_adresy v tabulce adres), pro které platí že město je Brno. Tedy vypíše všechny osoby s adresou v Brně. Je možné použít JOIN nebo LEFT JOIN.

SELECT – JOIN Seznam osob, které bydlí v Brně, nebo neznámo kde: SELECT osoby.jmeno, osoby.prijmeni, adresy.mesto FROM osoby LEFT JOIN adresy ON osoby.id_adresy = adresy.id_adresy WHERE (mesto = 'Brno') OR (mesto is NULL); Vybere osoby z tabulky spojené z osob a adres (spojovací podmínka říká, že na hodnotu v sloupci id_adresy se má navázat odpovídající záznam v tabulce adresy), pro které platí, že město je buď Brno nebo není zadané. V tomto případě je nutné použít LEFT JOIN, protože požadujeme i vypsání osob, které nemají žádnou adresu. Zjistit jestli je hodnota zadaná se musí pomocí konstrukce IS NULL (nelze používat mesto=NULL). Princip je tedy takový, že se vytvoří spojená tabulka a pak se omezí počet řádků (srov. s následujícím).

SELECT – pod-dotaz Seznam osob, které bydlí v Brně (s využitím pod-dotazu): SELECT osoby.jmeno, osoby.prijmeni, adresy_brno.mesto FROM osoby JOIN ( SELECT mesto,id_adresy FROM adresy WHERE mesto = 'Brno' ) as adresy_brno ON osoby.id_adresy=adresy_brno.id_adresy; Stejného efektu jako v předchozím případě je možné dosáhnout i využitím pod-dotazu. Pod-dotaz, tedy vnořený dotaz (tedy druhý dotaz shora) vybere z tabulky adres všechny adresy v Brně, vytvoří tak dočasnou tabulku (pojmenovanou jako adresy_brno). Hlavní dotaz (tedy první shora) spojí tuto dočasnou tabulku s tabulkou osoby, tedy vybere všechny osoby, které bydlí v Brně. Je nutné použít JOIN (mají se vypsat JEN osoby, které bydlí v Brně). Princip je tedy takový, že se nejprve omezí výběr a pak se tabulky spojí (srov. předchozí).

SELECT – pod-dotaz Seznam všech osob a jejich adresa, pokud bydlí v Brně: SELECT osoby.jmeno, osoby.prijmeni, adresy_brno.mesto FROM osoby LEFT JOIN ( SELECT mesto,id_adresy FROM adres WHERE mesto = 'Brno' ) as adresy_brno ON osoby.id_adresy=adresy_brno.id_adresy; Dotaz se liší od předchozího pouze použitím LEFT JOIN. Což znamená, že se při spojení vyberou všechny záznamy z tabulky osoby, a z tabulky adresy_brno pouze ty záznamy odpovídající spojovací podmínce. Protože tabulka adresy_brno obsahuje pouze brněnské adresy, tak budou adresy přiřazeny pouze k osobám, které bydlí v Brně.

SELECT, JOIN, pod-dotaz Výběr všech osob, které mají e-mail (s e-maily a s využitím JOINu): SELECT osoby.jmeno,osoby.prijmeni,kontakty.kontakt FROM (osoby JOIN kontakty ON osoby.id_osoby = kontakty.id_osoby ) NATURAL JOIN typy_kontaktu WHERE typy_kontaktu.nazev LIKE '%mail'; Vybere záznamy z tabulky, která vznikne spojením tabulky osob s tabulkou kontakty a dále s tabulkou typy_kontaktu. Pro druhé spojení se používá NATURAL JOIN, protože příslušné sloupce v tabulce typy_kontaktu a kontakty se jmenují stejně (id_typy_kontaktu), stejně tak by sel NATURAL JOIN použít pro první spojení. Operátor LIKE omezí výběr na všechny záznamy jejichž název typu kontaktu končí na 'mail'.

SELECT, JOIN, pod-dotaz Výběr všech osob, které mají e-mail (s e-maily a s využitím pod-dotazu): SELECT osoby.prezdivka, kontakty_emaily.kontakt FROM osoby JOIN ( SELECT kontakt,id_osoby FROM kontakty NATURAL JOIN ( SELECT id_typy_kontaktu FROM typy_kontaktu WHERE nazev LIKE '%mail') AS typ_email) AS kontakty_emaily ON osoby.id_osoby = kontakty_emaily.id_osoby; Dotaz využívá dva vnořené pod-dotazy, nejvnitřnější dotaz vybere z tabulky typů kontaktů pouze typ email (pravděpodobně pouze jeden záznam) a dočasnou tabulku pojmenuje jako typ_email. Tato tabulka se v prostředním dotazu spojí s tabulkou kontakty, protože je použitý JOIN, tak se vyberou pouze kontakty, jejichž typ je email. Výsledek prostředního dotazu se pojmenuje jako dočasná tabulka kontakty_emaily a dále se spojí s tabulkou osob, pro spojení je opět možné použít NATURAL JOIN.

SELECT, JOIN, pod-dotaz Výběr všech osob, které mají e-mail (bez e-mailů a s využitím pod-dotazu): SELECT jmeno,prijmeni FROM osoby WHERE id_osoby IN ( SELECT id_osoby FROM kontakty WHERE id_typy_kontaktu IN ( SELECT id_typy_kontaktu FROM typy_kontaktu WHERE nazev LIKE '%mail‚ ) ); Vybere všechny osoby pro které platí, že existují ve výsledku pod-dotazu (operátor IN). Pod-dotaz vybere všechny idčka všech osob z tabulky kontaktů (tabulka kontakty obsahuje sloupec id_osoby, který obsahuje hodnoty id_osoby z tabulky osoby). Pro které platí, že existují ve výsledku pod-dotazu (operátor IN). Nejvnitřnější pod-dotaz (3. v pořadí) vybere typy kontaktu e-mail. Tento způsob má tu nevýhodu, že není možné do výsledku zahrnout sloupce z jiné tabulky (není možné vypsat e-mail), výhodou je ale to, že může být srozumitelnější a je obecně mnohem rychlejší (pro tabulky s velkým množstvím záznamů).

SELECT, JOIN, pod-dotaz Výběr všech osob, které mají e-mail (bez e-mailů): SELECT osoby.jmeno, osoby.prijmeni FROM osoby WHERE EXISTS ( SELECT 1 FROM kontakty typy_kontaktu WHERE nazev LIKE '%mail' AND kontakty.id_typy_kontaktu = typy_kontaktu.id_typy_kontaktu ) AND osoby.id_osoby = kontakty.id_osoby ); Poslední varianta s využitím operátoru EXISTS, je poněkud exotická. Vybere všechny záznamy z tabulky osoby, pro které platí, že pod-dotaz vrátí nějaký řádek. Pod-dotaz obsahuje podmínku osoby.id_osoby=kontakty.id_osoby, vrátí tedy výsledek jen pro příslušnou osobu. Je možné si to představit tak, že pro každý řádek tabulky osoby se spustí pod-dotaz a pokud vrátí hodnotu 1, tak se řádek zahrne do výsledku hlavního dotazu.

http://www.xkcd.com/

SELECT – struktura příkazu SELECT [ ALL | DISTINCT ] výběrový_výraz1, výběrový_výraz2, … [ FROM odkazy_na_tabulky [ WHERE vyhledávací_podmínka ] [ GROUP BY { jméno_sloupce | výraz } [ ASC | DESC ], … ] [ HAVING vyhledávací_podmínka ] [ ORDER BY { jméno_sloupce | výraz } ] Další částí SELECT dotazu jsou agregační funkce, které těsně souvisí s klauzulemi GROUP BY a HAVING

SELECT – agregační funkce COUNT(*), COUNT(sloupec) – počet záznamů SUM(sloupec) – suma hodnot ve sloupci AVG(sloupec) – průměr hodnot ve sloupci MAX(sloupec), MIN(sloupec) – maximum/minimum hodnot ve sloupci počet záznamů: COUNT(sloupec) – počet hodnot (počítá duplicity) COUNT (DISTINCT sloupec) – počet unikátních hodnot COUNT(*) – zahrnuje i duplicity a prázdné řádky COUNT(*) – nelze použít v kombinaci s DISTINCT COUNT(*) a COUNT(sloupec) se chovají poměrně hodně odlišně. COUNT(*) počítá počet řádků tabulky, COUNT(sloupec) počítá počet hodnot ve sloupci (nezapočítávají se NULL), COUNT(DISTINCT sloupec) počítá počet unikátních hodnot ve sloupci. Při použití agregačních funkcí je dobré myslet na to, že SELECT vždy vrací tabulku, takže SELECT COUNT(*) vrátí tabulku, která obsahuje jeden sloupec COUNT a v něm jeden řádek, který obsahuje počet řádků tabulky osoby.

SELECT – agregační funkce počet e-mailů každé osoby, která má kontakt stačí tabulka kontakty výchozí stav: rozdělení do skupin podle sloupce v GROUP BY

SELECT – agregační funkce agregační funkce se aplikuj na každou skupinu zvlášť výsledek se zapíše do tabulky, kterou tvoří: sloupce z agregace výsledek agregační funkce pro každou skupinu je ve výsledné tabulce jeden řádek dochází ke sloučení (agregaci) řádků

SELECT – agregační funkce SELECT COUNT(*) FROM osoby; SELECT COUNT(*) FROM osoby NATURAL JOIN kontakty; osoby LEFT JOIN kontakty ON osoby.id_osoby = kontakty.id_osoby; SELECT COUNT(kontakt) FROM osoby LEFT JOIN kontakty ON osoby.id_osoby = kontakty.id_osoby; SELECT COUNT(DISTINCT id_osoby) FROM vrátí počet záznamů v tabulce osoby vrátí počet záznamů v tabulce osoby spojené s tabulku kontakty, což je totéž jako počet kontaktů (protože kontakt může být přiřazen jen jedné osobě) vrátí počet záznamů v tabulce, která obsahuje všechny osoby a u každé osoby všechny kontakty (vcelku neužitečný výsledek) vrátí počet hodnot ve sloupci kontakt v tabulce, která obsahuje všechny osoby a u každé osoby všechny kontakty (což je totéž jako počet kontaktů) Vrátí počet různých hodnot ve sloupci id_osoby, v tabulce osob s kontakty. Tedy vrátí počet osob, které mají nějaký kontakt.

SELECT – GROUP BY GROUP BY rozdělí tabulku na skupiny a pro každou skupinu zvlášť spustí agregační funkci. GROUP BY často obsahuje klíč tabulky. Počet kontaktů každé osoby která má alespoň jeden kontakt: SELECT COUNT(*), id_osoby FROM osoby JOIN kontakty ON osoby.id_osoby = kontakty.id_osoby GROUP BY osoby.id_osoby; Vypíše pouze počet kontaktů osob, které mají kontakt, protože je použitý INNER JOIN, tedy zdrojová tabulka je složena pouze z osob, které mají kontakty.

SELECT – GROUP BY Počet kontaktů všech osob (pokud osoba nemá kontakt je uvedena hodnota 1): SELECT COUNT(*), id_osoby FROM osoby LEFT JOIN kontakty ON osoby.id_osoby = kontakty.id_osoby GROUP BY osoby.id_osoby; Počet kontaktů všech osob: SELECT COUNT(kontakty.kontakt), id_osoby FROM Aby se vypsal i počet kontaktů pro osoby, které nemají kontakty, je nutné použít LEFT JOIN, tedy zdrojová tabulka musí obsahovat všechny záznamy z tabulky osoby. V tom případě ale funkce COUNT(*) vrátí pro osoby, které nemají žádný kontakt hodnotu 1 (protože vrací počet řádků a nikoliv počet hodnot a v každé seskupené tabulce bude existovat jeden záznam pro každou osobu, která nemá kontakt). Je tedy nutné použít funkci COUNT(sloupec), která vrátí počet hodnot v každé seskupené tabulce. Uvedený sloupec musí být z tabulky kontakty (aby pro osobu která nemá kontakt nebyla ve sloupci žádná hodnota).

COUNT vs. COUNT(*) COUNT(*) vrátí počet řádků skupiny

SELECT – GROUP BY Při použití agregace musí být všechny sloupce v částí SELECT také v části GROUP BY. Počet kontaktů každé osoby včetně jmen (musí se použít pod-dotaz): SELECT jmeno, prijmeni, pocet FROM osoby JOIN ( SELECT COUNT(kontakty.kontakt) AS pocet, osoby.id_osoby FROM osoby LEFT JOIN kontakty ON osoby.id_osoby = kontakty.id_osoby GROUP BY osoby.id_osoby ) AS osoby_pocet ON osoby.id_osoby = osoby_pocet.id_osoby; Protože se musí všechny sloupce v části SELECT FROM (seznam sloupců, který se má vybrat) vyskytovat také v části GROUP BY, musí se použít pod-dotaz k získání agregovaných hodnot (počet kontaktů každé osoby). Výsledek tohoto dotazu se jmenuje osoby_pocet, a obsahuje sloupce pocet a id_osoby, tato tabulka se spojí s tabulkou osoby a je tedy možné vypsat obojí (jak sloupce z tabulky osoby, tak hodnoty agregační funkce).

SELECT – HAVING Podmínka aplikovaná na agregaci SELECT jmeno, prijmeni, pocet FROM osoby JOIN ( SELECT COUNT(kontakty.kontakt) AS pocet, osoby.id_osoby FROM osoby LEFT JOIN kontakty ON osoby.id_osoby = kontakty.id_osoby GROUP BY osoby.id_osoby HAVING pocet > 2 ) AS osoby_pocet ON osoby.id_osoby = osoby_pocet.id_osoby; HAVING je podmínka aplikovaná na agregaci. Pro tento účel není možné použít WHERE, protože se vyskytuje ještě před GROUP BY (omezuje řádky tabulky před seskupením). HAVING omezuje řádky tabulky po agregaci, nejčastěji se tedy používá ve spojení s hodnotou agregační funkce, ale není to nutné. V tomto konkrétním případě by bylo možné HAVING nahradit podmínkou WHERE v hlavním dotazu.

SELECT – HAVING Počet kontaktů osob, které mají vztah: SELECT osoby.jmeno, osoby.prijmeni, osoby_pocet.pocet FROM osoby JOIN ( SELECT COUNT(kontakty.kontakt) AS pocet, kontakty.id_osoby FROM osoby LEFT JOIN kontakty ON osoby.id_osoby = kontakty.id_osoby GROUP BY osoby.id_osoby HAVING (( osoby.id_osoby IN (SELECT id_osoby1 FROM vztahy) ) OR ( osoby.id_osoby IN (SELECT id_osoby2 FROM vztahy) ) ) AS osoby_pocet ON osoby.id_osoby=osoby_pocet.id_osoby; Jako podmínka HAVING je zde uvedeno, že id_osoby musí být ve sloupci id_osoby1 nebo id_osoby2 v tabulce vztahy.

SELECT – HAVING Počet kontaktů osob, které mají vztah: SELECT osoby.jmeno, osoby.prijmeni, osoby_pocet.pocet FROM osoby JOIN ( SELECT COUNT(kontakty.kontakt) AS pocet, osoby.id_osoby FROM osoby JOIN kontakty ON osoby.id_osoby = kontakty.id_osoby GROUP BY osoby.id_osoby HAVING ( EXISTS (SELECT 1 FROM vztahy WHERE (id_osoby1 = osoby.id_osoby) OR (id_osoby2 = osoby.id_osoby) ) ) AS osoby_pocet ON osoby.id_osoby = osoby_pocet.id_osoby; Jako podmínka HAVING je zde uvedeno, že musí existovat takový záznam v tabulce vztahy, který má buď ve sloupci id_osoby1 nebo id_osoby2 hodnotu id příslušné osoby.

SELECT – struktura příkazu SELECT [ ALL | DISTINCT ] výběrový_výraz1, výběrový_výraz2, … [ FROM odkazy_na_tabulky [ WHERE vyhledávací_podmínka ] [ GROUP BY { jméno_sloupce | výraz } [ ASC | DESC ], … ] [ HAVING vyhledávací_podmínka ] [ ORDER BY { jméno_sloupce | výraz } ]

SELECT – ORDER BY Řadit je možné podle více kriterií. SELECT osoby.jmeno, osoby.prijmeni, adresy.mesto FROM osoby LEFT JOIN adresy ON osoby.id_adresy = adresy.id_adresy ORDER BY adresy.mesto DESC, osoby.prijmeni ASC, osoby.jmeno ASC; Seřadí tabulku sestupně (Z-A) podle města a osoby v každém městě budou seřazeny podle příjmení a podle jména vzestupně (A-Z).

SELECT – shrnutí SELECT co FROM odkud WHERE podmínky GROUP BY agregace HAVING vlastnosti ORDER BY jak Pořadí vyhodnocování: odkud – první zdroj dat JOIN – levá strana, pravá strana, podmínka podmínky – podmínky výběru agregace – seskupení výběru vlastnosti – výběr ze skupin co – omezení na sloupce jak – seřazení výsledku

UNION Sjednocení množin (dvou a více SELECTů) SELECT jmeno, prijmeni FROM osoby JOIN vztahy ON osoby.id_osoby = vztahy.id_osoby1 WHERE vztahy.id_osoby2 = 42 UNION SELECT jmeno, prijmeni FROM osoby JOIN vztahy ON osoby.id_osoby = vztahy.id_osoby2 WHERE vztahy.id_osoby1 = 42 ORDER BY jmeno, prijmeni Oba dotaz musí mít stejné sloupce (počet, datové typy, význam) Výsledky se uloží „pod sebe“, duplicity se vyřadí pokud není zadáno UNION ALL První dotaz vrátí jména a příjmení osob, které jsou ve vztahu uvedené jako druhé pro všechny vztahy ve kterých je první osoba s ID = 42. Druhý dotaz vrátí jména a příjmení osob, které jsou ve vztahu uvedené jako druhé a první osoba má ID 42. Sjednocením dostaneme výpis všech vztahů pro osobu s ID 42 a jméno a příjmení té druhé osoby ve vztahu. UNION není přímo součástí SELECTu, je na stejné úrovni jako klíčové slovo SELECT. Proto je na každé straně UNION kompletní SELECT s jedinou výjimkou. Tou je klauzule ORDER BY, která se nesmí vyskytovat uvnitř sjednocovaných SELECTů a píše až za poslední SELECT a vztahuje se k celému výsledku.

Hodnoty NULL Pro porovnání hodnot NULL se používá konstrukce IS NULL Osoby, které nemají e-mail: SELECT osoby.jmeno, osoby.prijmeni, kontakty_email.kontakt FROM osoby LEFT JOIN ( SELECT kontakt,id_osoby FROM kontakty NATURAL JOIN ( SELECT id_typy_kontaktu FROM typy_kontaktu WHERE nazev LIKE '%mail') AS typ_email) AS kontakty_email ON osoby.id_osoby = kontakty_email.id_osoby WHERE kontakty_email.kontakt IS NULL; Stejný dotaz jako dříve, ale nyní je v hlavním dotazu LEFT JOIN, tedy výpis všech osob a podmínka kontakt IS NULL, tedy omezení na osoby u kterých není zadaný kontakt. Protože tabulka kontaktů je před spojením omezena pouze na kontakty typu e-mail, tak dotaz vypíše hodnotu NULL pro všechny osoby, které nemají e-mail.

Hodnoty NULL Při výpisu hodnot NULL se může použít funkce COALESCE(): SELECT osoby.jmeno, osoby.prijmeni, COALESCE(kontakt, 'skupinovy@email.cz') FROM osoby LEFT JOIN ( SELECT kontakt,id_osoby FROM kontakty NATURAL JOIN ( SELECT id_typy_kontaktu FROM typy_kontaktu WHERE nazev LIKE '%mail') AS typ_email) AS kontakty_email ON osoby.id_osoby = kontakty_email.id_osoby; Funkce COALESCE dosadí místo hodnoty NULL zadanou hodnotu, tedy pro všechny osoby, které nemají zadaný e-mail se vypíše předdefinovaná hodnota skupinovy@email.cz.

Pohledy Trvalé virtuální tabulky definované dotazem. Automaticky se aktualizují. Jména a příjmení osob, které mají e-mail: CREATE VIEW osoby_emaily AS SELECT DISTINCT osoby.id_osoby,osoby.jmeno,osoby.prijmeni FROM ( osoby NATURAL JOIN kontakty ) NATURAL JOIN typy_kontaktu WHERE typy_kontaktu.nazev LIKE '%mail'; Pohled je definovaný SQL dotazem, z toho vyplývá, že se nejedná o relaci (může obsahovat stejné řádky). Pohled se automaticky aktualizuje z relací v databázi (pohled tedy neduplikuje data). Pohled bývá často pouze pro čtení. Pohled je dobrý k uložení, často používaných SQL dotazů, případně ke zjednodušení složitějších SQL dotazů.

Pohledy Vztahy, kde oba účastníci mají e-mail: SELECT vztahy.*, osoby1.prezdivka, osoby2.prezdivka FROM ( vztahy JOIN osoby AS osoby1 ON vztahy.id_osoby1 = osoby1.id_osoby ) JOIN osoby AS osoby2 ON vztahy.id_osoby2 = osoby2.id_osoby WHERE osoby1.id_osoby IN (SELECT id_osoby FROM osoby_emaily) AND osoby2.id_osoby IN (SELECT id_osoby FROM osoby_emaily); Dotaz využívá pohledu definovaného na předchozím slajdu. Pohled obsahuje IDčka, jména a příjmení všech osob, které mají e-mail. Tento dotaz tedy na tabulku kontakty naváže 2x tabulku osoby (2x protože tabulka vztahy se 2x odkazuje na tabulku osoby) a vybere z ní všechny záznamy pro které platí, že ID osoby je v pohledu osoby_emaily (tedy jedná se o osoby, která má e-mail).

SQL – shrnutí Pod-dotaz se musí použít při agregaci a výpisu více sloupců. JOIN se musí použít při získávání dat z více tabulek (dotazů). SQL je neprocedurální jazyk: Při psaní a ladění se musí postupovat hierarchicky, nikoliv sekvenčně. Komentáře se píší k celému dotazu. Pokud SQL dotaz nic nevypíše, neznamená to, že je špatně a naopak.