SQL (syntaxe a sémantika příkazů; vestavěné funkce, triggery, uložené procedury, příkazy pro definici dat; transakční zpracování; atomické operace; optimalizace dotazů)
Jazyk SQL obsahuje i vestavěné funkce, mezi ně patří především tzv. agregační funkce, ale dále do nich patří např. funkce pro práci s řetězci (SUBSTRING
, LOWER
atd.), pro zjištění aktuálního data a času atd. Množina dostupných funkcí je hodně závislá na zvoleném DBMS, kterým může být Oracle, Postgresql, SQL Server atd.
COUNT
– počet záznamů ve vrácené množině. Aplikuje-li se ve formě „COUNT(*)“, tak je vrácen počet všech záznamů; pokud je aplikován ve tvaru „COUNT(nazev_sloupce)
“, tak je vrácen počet záznamů, které nemají ve sloupci „nazev_sloupce“ hodnotu NULL
. AVG
– průměr dané hodnoty ve všech záznamech. SUM
– součet všech hodnot daného sloupce. MIN, MAX
– minimální, resp. maximální, hodnota daného sloupce v záznamech. Příklady
Počet všech produktů, které splňují podmínku, že ID
je větší než 1
SELECT COUNT(*) FROM [Products] WHERE nRowID > 1
Počet všech produktů, které mají vyplněný popis (tj. není NULL
)
SELECT COUNT(sDescription) FROM [Products]
Průměrná mzda zaměstnanců
SELECT AVG(mSalary) FROM [Zamestnanci]
Počet kusů všech produktů
SELECT SUM(nCount) FROM [Products]
Minimální a maximální mzda zaměstnanců
SELECT MIN(mSalary), MAX(mSalary) FROM [Employees]
Přetypování řetězce na celé číslo
CAST ('987' AS INT)
Definuje sadu příkazů, které lze použít pro vytváření, úpravu a odstraňování objektů v databázi. Nejčastěji spravovanými objekty jsou: tabulky, pohledy, procedury, funkce.
CREATE
– vytvoření objektu. ALTER
– úprava. V případě změny tabulky se může jednat o přidání/úpravu/odstranění sloupce, změny datového typu sloupce, změny relace a jiných integritních omezení. Příklad přidání sloupce do tabulky: ALTER TABLE [Nazev_Tabulky] ADD COLUMN [sValue3] Boolean
. DROP
– odstranění. Příklad odstranění procedury: DROP PROCEDURE [Procedura1]
. Příklady
Vytvoření tabulky
CREATE TABLE [Nazev_Tabulky] (nRowID Int PRIMARY KEY, sValue1 Varchar, sValue2 Varchar)
Vytvoření tabulky s tím, že je vynuceno zadání hodnoty pro název produktu
CREATE TABLE [Products] (nProductID Int PRIMARY KEY, sName NOT NULL)
Vytvoření tabulky s popisy produktů, které navazují na tabulku s produkty vytvořenou výše
CREATE TABLE [ProductDescriptions] (nProductID Int PRIMARY KEY, sDescription Varchar, CONSTRAINT vazbaProdukt FOREIGN KEY (nProductID) REFERENCES [Products] (nProductID))
Vytvoření tabulky s kontrolou, že je hodnota rodného čísla unikátní pro každého studenta (UNIQUE
)
CREATE TABLE [Students] (nStudentID Int PRIMARY KEY, sBirthNumber Varchar UNIQUE)
Vytvoření tabulky s kontrolou, že je hodnota platu vždy kladná hodnota (CHECK)
CREATE TABLE [Employees] (nEmployeeID Int PRIMARY KEY, sName Varchar, mSalary Decimal, CONSTRAINT plat CHECK (mSalary > 0))
Vytvoření tabulky s výchozí hodnotou na sloupci (DEFAULT)
CREATE TABLE [Nazev_Tabulky] (nRowID Int PRIMARY KEY, sValue1 Varchar, sValue2 Varchar DEFAULT 'výchozí hodnota')
Množina příkazů, které se využívají pro výběr, vkládání, úpravu a mazání dat v tabulkách.
INSERT
– vloží záznam do právě jedné tabulky. UPDATE
– upraví libovolný počet záznamů v právě jedné tabulce. DELETE
– odstraní libovolný počet záznamů z právě jedné tabulky. SELECT
– vybírá data z databáze, umožňuje výběr, agregaci a řazení dat. (odpovídá operaci projekce v relační algebře)
DISTINCT
– slouží k eliminaci duplikátů ve výsledku dotazu (ALL duplikáty ponechává) WHERE
– odpovídá operaci selekce v relační algebře FROM
– odpovídá kartézskému součinu z relační algebry ORDER BY
– uspořádá výpis sestupně (DESC) či vzestupně (ASC) GROUP BY
– umožňuje aplikovat souhrnné funkce, klauzule HAVING se aplikuje až po vytvoření skupin JOIN
– spojí dvě relace a vrátí jednu relaci, hlavní typy spojení: vnitřní, vnější
Příklady
Vložení produktu do tabulky
INSERT INTO [Products] (nProductID, sName) VALUES (1, „Produkt cislo 1“)
Úprava produktu
UPDATE [Products] SET sName = „Novy nazev produktu 1“ WHERE [nProductID] = 1
Odstranění všech produktů
DELETE FROM [Products]
Výběr všech produktů včetně jejich popisu
SELECT prod.nProductID, prod.sName, prod.sDescription
FROM [Products] AS prod
INNER JOIN [ProductDescriptions] prodDesc ON prod.nProductID = prodDesc.nProductID
Výběr všech produktů bez ohledu na to, mají vyplněný popis či nikoliv
SELECT prod.nProductID, prod.sName, prod.sDescription
FROM [Products] AS prod
LEFT OUTER JOIN [ProductDescriptions] prodDesc ON prod.nProductID = prodDesc.nProductID
Výběr skladů seřazených podle jejich naplnění sestupně
Předpokládejme tabulku se stavy produktů ve skladě: CREATE TABLE [ProductsInStores] (nStoreID INT, nProductID INT, nAmount INT, PRIMARY KEY (nStoreID, nProductID))
pak dotaz může vypadat následovně: SELECT nStoreID, SUM(nAmount)
FROM [ProductsInStores]
GROUP BY [nStoreID]
ORDER BY SUM(nAmount) DESC
Zpravidla se jedná o příkazy, které slouží k řízení transakcí, nastavení práv a jiné.
BEGIN
– spustí transakci s uvedeným názvem, který není povinný. Často se ještě uvádí úroveň izolace, která je použitá během zpracování příkazů kvůli předejití konkurenčním operacím. Příklad: BEGIN TRAN [MyTran1]
.
BEGIN
. Na toto je potřeba si dávat pozor, protože pokud provedené změny manuálně nepotvrdíte příkazem COMMIT
, neprojeví se. Databázový systém po nějakém specifikovaném timeoutu transakci zruší a změny se zahodí.
COMMIT
– potvrdí transakci. Příklad: COMMIT TRAN [MyTran1]
ROLLBACK
– vrátí provedené změny. Může se rušit jak celá transakce, tak její část od určitého bodu až po chvíli, kdy je ROLLBACK
volán (viz. SAVE
). Příklad: ROLLBACK TRAN [MyTran1]
SAVE
– tento příkaz není součástí standardu, ale většina db systémů jej podporuje. Ukládá stav transakce, do něhož je možné se vrátit, pokud není žádoucí vracet úplně celou transakci. Příklad: SAVE TRAN [MyCheckpoint1]
. Definice dle Wikipedie:
Atomická operace znamená, že její vykonání je nedělitelné – buď proběhne zcela úspěšně, nebo zcela neúspěšně. Atomickými operacemi jsou například: „vlož jeden záznam“, „zobraz jeden záznam“, apod.
Oproti tomu, vykonání neatomické operace je dělitelné: dojde-li při vykonávání příkazu k chybě, operace, které již byly vykonány, nebudou vráceny zpět. To se týká například operací, které mají vliv na větší množství řádků.
Příklad atomické a neatomické operace:
Vložení jednoho záznamu do tabulky
INSERT INTO [Products] (nProductID, sName) VALUES (1, „Muj produkt 1“)
Vložení více záznamů do tabulky překopírováním z jiné tabulky
INSERT INTO [Products] (nProductID, sName)
SELECT nProductID, sName FROM [Products2]
Je posloupnost operací (DML příkazů), které převedou datové schéma z jednoho konzistentního stavu do druhého.
O transakci platí, že je ACID:
Každá transakce má určitou úroveň izolace. Pokud se při vytvoření nespecifikuje, použije se výchozí úroveň.
Více transakcí může být spouštěno současně. Výhody jsou:
Nevýhody:
Neboli uváznutí, označuje stav, kdy transakce A čeká na prostředky, které drží transakce B a transakce B čeká na prostředky, které má uvolnit transakce A. Vždy se reší zaříznutím jedné z transakcí, nelze čistě vyřešit a je nutné jim předcházet.
Neopakovatelné čtení označuje stav, kdy si jedna transakce přečetla záznam, provedla nějaké příkazy a pak si tento záznam přečetla znovu a už měl jiné hodnoty.
Fantom označuje data, která na první pohled „záhadně“ unikají aktualizacím.
Jsou databázové objekty, které neobsahují data, ale programy, které se nad daty v databázi mají vykonávat. Mají své parametry a lokální proměnné, které nejsou zvenku vidět.
Uložená procedura je uložená (rozuměj: uložená v databázi). To znamená, že se k ní lze chovat stejně jako ke každému jinému objektu databáze (indexu, pohledu, triggeru apod.). Lze jí založit, upravovat a smazat pomocí příkazů dotazovacího jazyka databáze.
Pro psaní uložených procedur je obvykle používán specifický jazyk konkrétní databáze, který je rozšířením jejího dotazovacího jazyka. V případě Oraclu to je procedurální jazyk PL/SQL, u SQL Serveru se jedná o T-SQL.
Jedná se o uloženou sadu SQL příkazů, kterou lze parametrizovat. Má návratový typ a často se požaduje, aby byly deterministické. V praxi se to projevuje tak, že nesmí obsahovat prvky nedeterminismu jako například aktuální datum a čas atp.
Funkce je objekt jako každý jiný, takže ji lze spravovat pomocí jazyka DDL.
V databázi specifikuje činnosti, které se mají provést v případě definované události nad databázovou tabulkou. Definovanou událostí může být například vložení nebo smazání dat. Často slouží pro složitější kontrolu integrity dat.
Triggery jako takové jsou definovány ve většině moderních databázových systémů, ovšem mírně se liší v sémantice svého provedení.
Klíčové rozdíly jsou zejména v:
Syntax (databáze Oracle):
CREATE [OR REPLACE] TRIGGER jmeno {BEFORE | AFTER | INSTEAD OF}
udalost [FOR EACH ROW] [WHEN (podminka)]
blok
UPDATE
, DELETE
nebo INSERT
, případně jejich kombinace (zpravidla oddělené klíčovým slovem OR) BEFORE
triggery jsou spouštěny před provedením události, AFTER
triggery až po provedení události FOR EACH ROW
) INSERTING, UPDATING, DELETING
3) Robin Hood osobně používal tento Trigger
CREATE TRIGGER uprav_platy BEFORE UPDATE OF plat ON people FOR EACH ROW BEGIN IF (:NEW.plat>30000) THEN :NEW.plat:=28000; END IF; /* prilis by se namlsali */ IF (:NEW.plat<12000) THEN :NEW.plat:=15000; END IF; /* a chudym pridame */ END;
Existuje celá řada způsobů, jakými lze ovlivnit rychlost zpracování dotazu, níže je seznam těch základních.
SELECT * FROM [Products]
“ vybere všechny sloupce z tabulky, které možná ani nepotřebujeme, ale přinese také zpomalení z toho důvodu, že systém si musí nejdříve vytáhnout seznam sloupců z definice tabulky, aby je mohl zobrazit. Navíc takový dotaz není odolný proti změnám schématu tabulky. LIKE
– Obecně není vhodné operátor používat ve tvaru LIKE '%Karel%', v tom případě musí databáze projít všechny zbývající výskyty. To při omezení vhodnou podmínkou nemusí vadit. Tvar LIKE 'Karel%' je naprosto v pořádku a indexy v tomto případě fungují, stejně tak tvar bez procent. Většina dnešních nástrojů nabízí možnost zobrazení plánu provedení dotazů, který velice usnadní jejich ladění.
LIKE
je výběrový operátor používaný na řetězce, který může obsahovat tzv. wildcards.
Příklad výběru zaměstnanců, jejichž příjmení začíná na „Eich“
SELECT * FROM [Employees] WHERE sLastName LIKE 'Eich%
'
Pohled je databázový objekt, který uživateli poskytuje data ve stejné podobě jako tabulka. Na rozdíl od tabulky, kde jsou data přímo uložena, obsahuje pohled pouze předpis, jakým způsobem mají být data získána z tabulek a jiných pohledů.
Takto se nazývá speciální varianta pohledů, u nichž jsou výsledky volání ukládány. Rozdíl oproti normálním pohledům je ten, že při opakovaném volání přináší znatelné urychlení a navíc je možné v nich upravovat data. Podmínkou úpravy je to, že v pohledu musí být vybrány všechny sloupce primárního klíče tabulky, jejíž data aktualizujeme. Zpravidla se aktualizují pohledy nad jednou tabulkou, aby byly úpravy průhledné a nedocházelo k nechtěným změnám. Tuto možnost podporuje například Oracle, SQL Server už nikoliv.
Příklady
Vytvoření pohledu pro výběr produktů včetně jejich popisu
CREATE VIEW [View_Product] AS
SELECT prod.nProductID, prod.sName, prod.sDescription
FROM [Products] AS prod
INNER JOIN [ProductDescriptions] prodDesc ON prod.nProductID = prodDesc.nProductID
Moderní databázové systémy většinou umožňují integraci klasických programovacích jazyků do procedur, funkcí a triggerů, takže tímto způsobem je možné s výhodou využít například C++ nebo Javu tam, kde je SQL slabé.
Existují 4 druhy úrovní izolace dle standardu:
Petr Koutný, ICQ: 223-009-182. Nemám patent na rozum, takže klidně něco upravte, pokud vám to přijde nesmyslný
Otázku si přečetl pan RNDr. Vlastislav Dohnal a rámcově prošel. Jeho podněty pro doplnění textu, opravy nesrovnalostí a odstranění matoucích či k otázce se nevztahujících textů byly do otázky zaneseny. Tato kontrola je jen rámcová, stále se může stát, že v otázce zůstala zapomenutá chybka či nesrovnalost, vyučující za toto nenese odpovědnost, berte tuto rámcovou kontrolu jako formu pomoci od vyučujících pro studenty.
Diskuze
Napadlo nas, jestli by jeste nestalo zato vic rozepsat select, vysvetlit vic where Order by, having …co myslite?
Tím „SQL Serverem“ se myslí Microsoftí SQL Server?
Ano - SQL Serverem se myslí MS SQL Server.
podmínky dotazu – pořadí podmínek v klauzuli WHERE by se mělo psát v pořadí od těch více selektivních k méně selektivním. Například dotaz „SELECT Jmeno, Prijmeni FROM [Lide] WHERE Pohlavi = 2 AND Vek > 18“ se takto vykoná rychleji, než kdyby se použila podmínka „Vek > 18 AND Pohlavi = 2“, protože omezení podle pohlaví vybere méně záznamů než omezení na věk.
predom sa ospravedlnujem za mozno hlupy dotaz, celkom ma to pomylilo…takze logicku podmienku db spracovava sekvencne? najskor spravi prienik s prvym obmedzenim a potom s druhym?
Kdyby ji totiž nezpracovával postupně, tak bys nebyl schopný optimalizovat dotazy v tom smyslu, jaký jsi zmínil.
ved jasne, pri logickych spojkach kde plati komutativnost asi nie no ..preto sa pytal ci je to tak implementovane (bo ked selsky prechadzas tabulku tak ides po zazname a chceckujes obmedzenia, namiesto toho aby som prechadzal tabulku viac krat )
No on to ani sekvencne zpracovavat nemusi, zalezi kolik to prochazi zaznamu. Je to dost neefektivni pro velke mnozstvi zaznamu. Rekl bych, ze je to zpracovavano spise pres indexy nebo index-sekvencnim zpusobem. Ale muze to prochazet tak, ze najde zaznamy vyhovujici prvni podmince a k nim pak zaznamy vyhovujici druhe podmince, tedy jak je zde zminovano. Nebo si muze vytvorit jakousi kapsu odkazu na zaznamy, ktere obsahuji danou hodnotu pohlavi a tu proniknout s kapsou pro hodnotu veku. Take jsem nekde cetl o indexu pro klic slozeny z vice atributu, tedy, ze by byla vytvorena indexova struktura pro dvojici (pohlavi,vek).
Ale kazdopadne jak je to tu psano, tak to neplati vzdy. Citace: „se takto vykoná rychleji, než kdyby se použila podmínka „Vek > 18 AND Pohlavi = 2“, protože omezení podle pohlaví vybere méně záznamů než omezení na věk.“
Priklad: přdpokladám, že strukturu dat nezname. Mějme tabulku
pohlavi | vek
I kdyz samozrejme, kdyz vime ze vybirame napriklad: „studentka FI AND vek >20“, tak je to jasna optimalizace oproti dotazu „vek >20 AND studentka FI“.
Takze se omlouvam, v urcitych pripadech, kdyz vime na jakych datech provadime dotazy se jedna o optimalizaci.
lol, ten bol dobry :))
Inak ja som tiez prvy krat pocul o takejto 'optimalizacii' az tu a to som mal aj Architekturu RDBS s p.Drasilom…
jj..suhlas, ja uz som nechcel rypat, bez konkretneho prikladu je bezpredmetne pisat ake poradie bude vyhodnejsie.
Super příklad, já bych tu „studentku FI“ klidně dal přímo do textu vypracování otázky, namísto toho nudného příkladu, co tam je teď Teda určitě aspoň já, kdybych tohle dostal u zkoušky, ten příklad použiju - je vtipný a aspoň to vyvolá u komise dobrou náladu.
Příklad by byl super, bohužel to není obecná pravda. Tohle všechno má na starosti optimalizátor dotazu, který si s tím poradí a jako první provede ty nejvíce omezující úkony, stejně jako u JOINů. Nedá se tedy rozhodně říct, že by to platilo obecně, spíše pochybuji, že ještě existuje nějaký databázový server, na kterém by to byla pravda. (Vlastní praxe, odzkoušeno na MS SQL Server 2005).
Uložená procedúra (stored procedure) je dávka (batch) SQL príkazov trvalo uložená na disku ako pomenovaný databázový objekt (podobne ako je databázovým objektom napr. tabuľka alebo pohľad) v konkrétnej databáze na SQL serveri.
Uložené procedúry sú v mnohom podobné podprogramom resp. procedúram, ktoré poznáme z procedurálnych programovacích jazykov. Môžu mať (no samozrejme nemusia) vstupné i výstupné parametre, možno v nich používať lokálne premenné, riadiace konštrukcie ako sú cykly či podmienky, a tiež je možné volať z jednej uloženej procedúry inú uloženú procedúru. Po svojom vykonaní uložená procedúra vracia tzv. status hodnotu indikujúcu či daná uložená procedúra prebehla v poriadku. Uložené procedúry však priamo nevracajú hodnoty (ako funkcie) a tiež ich nemožno použiť priamo vo výraze.
Chtel bych jen podotknout, ze LIKE muze s indexy spolupracovat krasne, ovsem asi ne ve vsech pripadech. Pokud je v tabulce sloupec, ktery nabyva treba 10ti hodnot a je na nem index, a cela tabulka ma treba statisice radku, pak zde i LIKE funguje bez problemu rychle (potvrzeno zkusenostmi s MySQL)
Domnívám se, že obecně nelze v jazyce SQL jména objektů obalovat hranatými závorkami. Takovou syntax dovoluje pouze SQL server. Jak MySQL tak PostgreSQL hlásí podobný dotaz jako syntaktickou chybu. Podle mých znalostí se v PostgreSQL používají klasické uvozovky, v MySQL zpětné apostrofy:
Abyste mi věřili, přidávám výpisy z řádkových klientů mysql a psql. V textu jsem o tomto připsal poznámku.
mysql> select [User] from users;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '[User] from users' at line 1
brackets=# select * from [users];
ERROR: syntax error at or near “[“
LINE 1: select * from [users];