# Structured Query Language

- dotazovací jazyk pro relační SŘBD
- ISO standard jazyka SQL
	- ISO/EIC 9075
	- 1986, 1989, **1992**, 1999, 2003, 2006, 2008, 2011, 2016, 2019, 2023
- komponenty:
	- DDL - Data Definition Language
	- DML - Data Manipulation Language
	- DCL - Data Control Language
	- TCL - Transaction Control Language

**Vlastnosti a použití SQL**
- neprocedurální deklarativní jazyk
- vychází z jazyka SEQEL
- slouží k vytvoření databáze a struktury relací (tabulek)
- uživatelé jazyka
	- administrátor (DBA)
	- management
	- vývojář aplikace
	- koncový uživatel

**Základní příkazy**
- DDL
	- `CREATE TABLE`, `ALTER TABLE`, `DROP TABLE`
	- `CREATE VIEW`, `DROP VIEW`
	- `CREATE INDEX`, `DROP INDEX`
- DML
	- `SELECT`
	- `INSERT`, `UPDATE`, `DELETE`
- DCL a TCL
	- `GRANT`, `REVOKE`
	- `COMMIT`, `ROLLBACK`

**Jak psát příkazy**
- každý příkaz musí začínat na nové řádce
	- může být zapsán na více řádek
- SQL rozlišuje
	- rezervovaná slova - nejsou case-sensitive
	- názvy objektů - mohou být case-sensitive
- rezervovaná slova nesmí být dělená do více řádků
- každý příkaz SQL musí být zakončen středníkem
- řetězce v příkazu musí být uzavřeny v apostrofech

## DML

**Příkaz SELECT**
- příkaz `SELECT` nebo jeho části jsou součástí jiných příkazů
- zjednodušená syntaxe

```sql
SELECT [DISTINCT] {* | [sloupec_vyraz [[AS]
alias] [,...]}
FROM tabulka [alias] [,...]
[WHERE podmínka]
[GROUP BY seznam_neagregovaných_sloupců_výrazů]
[HAVING podmínka]
[ORDER BY seznam_řazených_sloupců_výrazů];
```

**Agregované funkce**
- `COUNT(sloupec)`
	- počet neprázdných hodnot sloupce
- `SUM(sloupec)`
	- součet neprázdných hodnot sloupce
- `AVG(sloupec)`
	- aritmetický průměr neprázdných hodnot sloupce
- `MIN(sloupec)`
	- minimální hodnota sloupce
- `MAX(sloupec)`
	- maximální hodnota sloupce

**Vložení záznamu do tabulky**
- jedním příkazem `INSERT` lze vložit jen jeden záznam do jedné tabulky
- registrace čtenáře Jana Nováka

```sql
INSERT INTO Čtenář (Č_čt, Jméno) VALUES (123, 'Jan Novák');
```

**Změna záznamů tabulky**
- jedním příkazem `UPDATE` lze modifikovat hodnoty několika záznamů jedné tabulky
- uložení adresy čtenáři č. 123

```sql
UPDATE Čtenář SET Adresa = 'Univerzitní 8, Plzeň'
WHERE Č_čt = 123;
```

**Zrušení záznamu tabulky**
- jedním příkazem `DELETE` lze zrušit více záznamů jedné tabulky
- zrušení (smazání) všech rezervací čtenáře č. 123

```sql
DELETE FROM Rezervace WHERE Č_čt = 123;
```

## DDL

**Identifikátory**
- názvy tabulek, pohledů, sloupců a dalších databázových objektů
- názvy objektů jsou u mnoha SŘBD case-sensitive
- max. velikost 128 znaků
- povoleny malá a velká písmena, cifry a podtržítko
	- musí začít písmenem
- nesmí obsahovat diakritická znaménka a bílé znaky

**Vybrané datové typy**
+ textové znaky a řetězce
	- `CHARACTER`, `CHARACTER VARYING`
- přesné matematické výpočty
	- `NUMERIC`, `DECIMAL`, `INTEGER`
- přibližné matematické výpočty
	- `FLOAT`, `REAL`, `DOUBLE PRECISION`
+ datum a čas
	+ `DATE`, `TIME`, `TIMESTAMP`
+ rozsáhlé objekty
	+ `BINARY LARGE OBJECT`, `CHARACTER LARGE OBJECT`

**Definice tabulky**
- příkazem `CREATE TABLE` vytváříme tabulku, ve které
	- definujeme její jméno
	- zavedeme alespoň jeden sloupec (a jeho datový typ)
	- můžeme a nemusíme definovat
		- výchozí hodnotu, nepojmenovaná integritní omezení
	- můžeme zavést pojmenovaná integritní omezení vázané s tabulkou
	- seznam sloupců a integritních omezení je oddělován čárkou a uzavřen v závorce

```sql
CREATE TABLE Kluby (
	Id_klubu NUMERIC PRIMARY KEY,
	Název CHARACTER VARYING(30) NOT NULL,
	Založen DATE
);
```

**Logické vs. fyzické datové typy**

| logický | SŘBD Oracle | SŘBD MariaDB |
| ---- | ---- | ---- |
| CHARACTER | CHAR | CHAR |
| CHARACTER VARYING | VARCHAR2 | VARCHAR |
| NUMERIC | NUMBER | NUMBER |
| DECIMAL | NUMBER | DECIMAL |
| INTEGER | NUMBER | INT |
| FLOAT | NUMBER | FLOAT |
| REAL, DOUBLE PRECISION | NUMBER | DOUBLE |
| DATE, TIME | DATE | DATE, TIME, TIMESTAMP |
| TIMESTAMP | DATE | TIMESTAMP |
| BINARY LARGE OBJECT | BLOB | BLOB |
| CHARACTER LARGE OBJECT | CLOB | TEXT |

**Nepojmenovaná integritní omezení**
- každý sloupec může zahrnout tato integritní omezení
- `NOT NULL` - vyžadovaná hodnota
- `UNIQUE` - unikátní
- `PRIMARY KEY` - primární klíč
- `CHECK` - omezení podmínkou

**Pojmenovaná integritní omezení**
- začínají klíčovým slovem `CONSTRAINT` následovaného názvem omezení
- poté jedna z uvedených možností nahoře (kromě `NOT NULL`)
- zápis pokračuje seznamem sloupců tabulky, pro které je omezení definováno
- některá omezení mají další konstrukce v zápise

**Primární klíč**
- maximálně jeden pro tabulku
- nepojmenovaná varianta
	- `id_klubu NUMBER PRIMARY KEY`
- pojmenovaná varianta
	- `CONSTRAINT kluby_pk PRIMARY KEY (id_klubu)`
	- umožňuje složený PK

**Alternativní klíč**
- nepojmenovaná varianta
	- `nazev VARCHAR2(30) NOT NULL UNIQUE`
- pojmenovaná varianta
	- `CONSTRAINT nazev_un UNIQUE (nazev)`

**Cizí klíč**
- pouze pojmenovaná varianta

```sql
CONSTRAINT exemplar_fk1
FOREIGN KEY (isbn)
REFERENCES kniha (isbn)
```

- možno doplnit o reakci na rušení/aktualizaci prvku v nadřízené tabulce

```sql
ON DELETE NO ACTION
ON DELETE RESTRICT
ON DELETE SET NULL
ON DELETE CASCADE
ON UPDATE NO ACTION
ON UPDATE RESTRICT
ON UPDATE SET NULL
ON UPDATE CASCADE
```

- příklad

```sql
CONSTRAINT exemplar_fk1
FOREIGN KEY (isbn)
REFERENCES kniha (isbn)
ON DELETE NO ACTION
ON UPDATE NO ACTION
```

**Výběrová podmínka** (`CHECK`)
- stanovení hodnot sloupce výčtem nebo podmínkou
- nepojmenovaná varianta

```sql
...
semestr CHAR(2) NOT NULL
CHECK (semestr IN ('ZS', 'LS'))
...
kladne_cislo NUMBER
CHECK (kladne_cislo > 0)
...
```

- pojmenovaná varianta

```sql
CONSTRAINT ruzne_tymy
CHECK (id_domaci <> id_hoste)
```

**Kompletní vytvoření tabulky**

```sql
CREATE TABLE zapas (
	id_zapasu NUMBER PRIMARY KEY,
	misto VARCHAR2(100) NOT NULL,
	datum_cas DATE,
	id_domaci NUMBER,
	id_hoste NUMBER,
	goly_domaci NUMBER DEFAULT 0,
	goly_hoste NUMBER DEFAULT 0,
	CONSTRAINT zapas_fk1 FOREIGN KEY (id_domaci)
	REFERENCES kluby(id_klubu),
	CONSTRAINT zapas_fk2 FOREIGN KEY (id_hoste)
	REFERENCES kluby(id_klubu),
	CONSTRAINT ruzne_tymy CHECK (id_domaci <> id_hoste)
);
```

**Modifikace tabulky**
- provádí se příkazem `ALTER TABLE`
- lze měnit
	- název, sloupec, integritní omezení
- lze přidat/zrušit sloupce
	- ideálně u prázdné tabulky
	- lze přidat nebo zrušit více sloupců jedním příkazem
- lze přidat/zrušit pojmenovaná integritní omezení
	- jen jedno jedním příkazem

**Indexy**
- datová struktura
	- logické uspořádání prvků relace podle hodnot vybraných sloupců
	- má za úkol zrychlit operaci `SELECT` nad danou tabulkou
	- zpomaluje operace `INSERT`, `UPDATE` a `DELETE`
- index je tvořen pro jeden nebo skupinu sloupců
- index může být
	- unikátní (automaticky pro integritní omezení)
	- dovoluje opakování hodnot (ručně tvořené, např. pro cizí klíče)

```sql
-- Unikátní index
CREATE UNIQUE INDEX kluby_pk_idx
ON kluby (id_klubu);
-- Index dovolující opakovat hodnoty
CREATE INDEX zapas_fk1_idx
ON zapas (id_domaci);
-- Zrušení indexu
DROP INDEX kluby_pk_idx;
DROP INDEX zapas_fk1_idx;
-- zruší je i DROP TABLE
```

**Databázový pohled**
- virtuální relace, která fyzicky neexistuje
- poskytuje výsledek jedné nebo více relačních operací
	- definice spojena s příkazem `SELECT`
	- přiděluje příkazu `SELECT` jméno, pod kterým je uložen v databázi
- datová struktura výhradně ke čtení
	- výjimkou jsou aktualizovatelné pohledy
- čtenáři a jejich výpůjčky

```sql
CREATE VIEW vypujcky_ctenare AS
SELECT c.jmeno, v.inv_c
FROM ctenar c, vypujcka v
WHERE c.id_ctenar = v.id_ctenar;
```

- statistika tabulky exemplář

```sql
CREATE VIEW statistika (zeme, pocet, soucet)
SELECT zeme_vydani,
COUNT(inv_c),
SUM(cena)
FROM exemplar
GROUP BY zeme_vydani;
```

- zrušení: `DROP VIEW vypujcky_ctenare;`
- pohled se může stát nevalidním, pokud bude smazána tabulka či pohled, který je jím používán

## DCL

**Role a oprávnění**
- DB administrátor může uživateli udělit
	- systémovou roli, např. `CONNECT`, `RESOURCE`
	- systémové oprávnění, např. `UNLIMITED TABLESPACE`
- uživatel databáze může jinému uživateli udělit
	- uživatelskou roli
	- oprávnění k přístupu k jeho databázovému objektu
	- oprávnění předávat přidělený přístup dalším
- role je množinou systémových nebo objektových oprávnění
+ vybraná objektová oprávnění
	- `ALL PRIVILEGES`
	- `CREATE`, `ALTER`, `DROP`
	- `INSERT`, `UPDATE`, `DELETE`, `SELECT`

**Přidělení přístupu k objektům**
- příkazem `GRANT` je možné přidělit jednomu či více uživatelům
	- jednu či více rolí
	- jedno nebo více systémových oprávnění
	- jedno nebo více oprávnění k jednomu DB objektu
- konstrukcí `IDENTIFIED BY` je možné nastavit heslo k přístupu
- konstrukcí `WITH ADMIN OPTION` možnost předávat přidělené systémové oprávnění dalším uživatelům
- konstrukcí `WITH GRANT OPTION` možnost předávat přidělené objektové oprávnění dalším uživatelům

```sql
GRANT UNLIMITED TABLESPACE TO zima;
GRANT SELECT ON osoby TO PUBLIC;
GRANT INSERT, UPDATE, DELETE ON osoby
TO rychlik WITH GRANT OPTION;
```

**Odebrání přístupu**
- příkazem `REVOKE` lze odebrat jednomu nebo více uživatelům
	- jednu či více rolí
	- jedno nebo více systémových oprávnění
	- jedno nebo více oprávnění k jednomu DB objektu
- vždy možné odebrat
	- ty role a oprávnění, která byla přidělena
	- těm uživatelům, kterým byla přidělena

```sql
REVOKE UNLIMITED TABLESPACE FROM zima;
REVOKE SELECT ON osoby FROM PUBLIC;
REVOKE INSERT, UPDATE, DELETE ON osoby
FROM rychlik;
```