Relační Databáze

Většina aplikací, zejména těch webových, potřebuje manipulovat s daty. Může se jednat třeba o správu objednávek, produktů na eshopu nebo bankovních transakcí.

Vzhledem k tomu, že databáze jsou velice komplexní téma, tak si v této lekci projedeme jen základy. Pokud vás ale databáze zaujmou, tak je dobré se podívat po dalších materiálech, například na W3Schools.

Nad daty provádíme čtyři druhy operací - vytváření, čtení, úpravu a mazání. Tyto operace se sdružují do zkratky CRUD (Create, Read, Update, Delete).

Existují různé možnosti, kam data ukládat. Mohli bychom například vše zapisovat do jednoho souboru. Brzy bychom ale zjistili, že se jedná o velice neefektivní způsob - operace nad daty by s rostoucím počtem záznamů začaly být pomalé. V těchto situacích nastupují na scénu databáze (resp. databázové systémy).

Jedná se o vysoce sofistikovaná řešení různých výrobců (zmínit můžeme třeba Oracle nebo MySQL). Výhodou je, že tyto systémy mají společný způsob, jakým se s nimi komunikuje (API) - prostřednictvím jazyka SQL. Nemusí nás tedy zajímat, jak databáze funguje uvnitř.

Základem relačních databází jsou tabulky. Můžeme si je představit jako jeden list sešitu MS Excel (celý sešit by pak odpovídal databázi). Jednotlivé řádky tabulky jsou záznamy. Ty se skládají z několika atributů (sloupců). Řádky a sloupce odpovídají Excelovým řádkům a sloupcům.

Můžeme mít například tabulku OBJEDNAVKA. Bude tvořena sloupci ID_OBJEDNAVKY, ID_ZAKAZNIKA, DATUM, CENA. Jednotlivé záznamy představují jednotlivé objednávky - víme tedy kdy si kdo udělal objednávku, a kolik za ni zaplatil.

SQL

SQL (Structured Querying Language - Strukturovaný dotazovací jazyk) nám umožňuje komunikovat s databází. Výrobci jednolivých databází obvykle jazyk v některých oblastech rozšiřují, základ je ale společný a standardzivaný. Kromě práci s daty (CRUD) se jazyk používá pro vytváření tabulek a dalších objektů, pro správu uživatelů databáze apod.

SQL příkazy mohou být do databáze posílány z webové aplikace (Python, Javascript, ...), z terminálu, nebo třeba z aplikace přímo určené pro správu databáze. Je zvykem jednotlivé příkazy jazyka psát VELKÝMI PÍSMENY. Příkazy oddělujeme středníkem ;. Jednořádkové komentáře uvozujeme dvěma spojovníky -- a víceřádkové komentáře píšeme mezi /* a */.

Pojďme se podívat na některé z příkazů, které SQL podporuje.

Tabulky

Pro vytvoření tabulky použijeme příkaz CREATE TABLE, následovaný jménem tabulky a definicí jednotlivých sloupců. U sloupců definuje jméno, typ a případně další vlastnosti.

/* Vytvoří tabulku ROBOT se sloupci ID, NAME a TYPE.
   ID je celé číslo, NAME a TYPE jsou řetězce.
*/
CREATE TABLE ROBOT (
    ID      INT     PRIMARY KEY,
    NAME    TEXT,
    TYPE    TEXT
)

Význam PRIMARY_KEY si vysvětlíme později. Pokud bychom chtěli tabulku smazat, tak použijeme DROP TABLE JMENO_TABULKY. Jen pozor - spolu s tabulkou se smažou všechny záznamy v ní obsažené.

INSERT

Jakmile máme vytvořenou tabulku, můžeme do ní vkládat záznamy. Děláme tak pomocí příkazu INSERT. Uvedeme jméno tabulky a pak hodnoty, představující záznam (nebo záznamy), které se mají vložit.

-- Vloží do tabulky ROBOT nového Robota s ID 1, jménem Jim a typem AGGRESIVE
INSERT INTO ROBOT (ID, NAME, TYPE) VALUES (1, "Jim", "AGGRESSIVE");

-- Vloží do tabulky ROBOT další dva Roboty
INSERT INTO ROBOT (ID, NAME, TYPE) VALUES (2, "John", "DEFENSIVE"),(3, "Jack", "DEFENSIVE");

SELECT

Když už máme i nějaké zaznámy, tak je dobré mít způsob, jak je číst. Slouží k tomu mocný příkaz SELECT, který v nejzákladnější podobě očekává seznam sloupců, který se má pro jednotlivé záznamy vypsat, a jméno tabulky, ze které se mají data číst. Seznam sloupců můžeme nahradit hvězdičkou *, pokud chceme vypsat hodnoty všech sloupců.

-- vypíše hodnoty všech sloupců pro všechny roboty
SELECT * FROM ROBOT;

-- vypíše jen jména všech robotů
SELECT NAME FROM ROBOT;

Příkaz SELECT podporuje třeba také filtrování dat (ukážeme si později), řazení (ORDER BY) a seskupování dat (průměr - AVG, suma - SUM, ...)

UPDATE

V případě, že chceme data upravit (například změnit jméno robota), tak použijeme příkaz UPDATE. I ten očekává jméno tabulky, jejíž záznamy se mají upravit. Kromě toho také zadáme nové hodnoty pro jednotlivé sloupce. Hodnoty sloupců, které neuvedeme, zůstanou nezměněné.

-- nastaví všem robotům typ na AGGRESSIVE
UPDATE ROBOT SET TYPE = "AGGRESSIVE";

DELETE

A konečně poslední oprací v CRUD je mazání. V SQL se záznamy mažou pomocí příkazu DELETE. I zde, stejně jako u ostatních CRUD příkazů, uvádíme jméno tabulky.

-- smaže všechny roboty
DELETE FROM ROBOT;

WHERE

Nejspíš vás napadalo, že pokud bychom vždy četli, upravovali nebo mazali všechna data v tabulce, tak by systém nebyl moc dobře použitelný. Naštěstí ale můžeme pomocí příkazu WHERE ovlivnit, nad jakými záznamy se bude operace provádět.

Za WHERE se píší podmínky (spojované pomocí AND nebo OR), které musí platit, aby se záznam přidal do množiny, nad kterou se bude operace provádět. V podmínkách je možné použít různé operátory:

  • rovnost: WHERE SLOUPEC = HODNOTA
  • nerovnost: WHERE SLOUPEC > HODNOTA (>, <, <>, ...)
  • jedna z hodnot: WHERE SLOUPEC IN (HODNOTA_1, HODNOTA_2)
  • podřetězec: WHERE SLOUPEC LIKE %HODNOTA%
-- vypíše všechny řádky o robotech, které mají typ AGGRESSIVE
SELECT * FROM ROBOT WHERE TYPE = "AGGRESSIVE";

-- přejmenuje roboty, jejichž jména začínají na J, na Jimmy
UPDATE ROBOT SET NAME = "Jimmy" WHERE NAME LIKE "J%";

-- smaže robota s ID větším než 1
DELETE FROM ROBOT WHERE ID > 1;

Primární klíče

Každá tabulka by měla mít soupec, který jednoznačně identifikuje jednotlivé řádky. Ve sloupci musí být unikátní hodnoty. Může se jednat o uměle vytvořené číslo (nejčastěji nazývané ID), nebo může jít o unikátní identifikátor z reálného světa. Pozor ale na to, že ne každý na první pohled unikátní identifikátor je skutečně unikátní - je například možné, aby dvě osoby měly stejné rodné číslo. Je tedy obecně lepší používat uměle vytvořené primární klíče.

Primární klíče se používají proto, že zrychlují operace nad daty (rychle se podle nich vyhledává) a také proto, že snižují riziko duplicitních dat v databázi. Při vytváření tabulky zadáme u sloupce, který má být primárním klíčem, vlastnost PRIMARY KEY.

Cizí klíče

Cizí klíče - FOREIGN KEY - se využívají pro zachycení vazby mezi tabulkami. V dceřiné tabulce máme sloupec představující cizí klíč, jehož hodnoty se odkazují na primární klíč jiné tabulky.

Například tabulka OBJEDNAVKA má cizí klíč ID_ZAKAZNIKA. Tento cizí klíč se odkazuje na primární klíč tabulky ZAKAZNIK. Tím zaručíme, že každá objednávka musí být "napojená" na existujícího zákazníka.

Cizí klíče

zdroj obrázku

Spojování tabulek

Často potřebujeme v jednom dotazu číst data z více tabulek. Používáme k tomu příkaz JOIN, který je součástí příkazu SELECT. V základní verzi vezme JOIN záznamy z jedné tabulky a připojí k nim odpovídající záznamy z druhé tabulky. Na takto nově vzniklý řádek je možné udělat JOIN s další tabulkou.

To, co považujeme za "odpovídající záznam" zapíšeme jako součást JOIN (za klíčové slovo ON). Nejdříve ale musíme zadat jméno tabulky, kterou chceme připojit.

-- vypíše jména a příjmení zákazníků, kteří udělali objednávku za více než 500 Kč

SELECT ZAKAZNIK.JMENO, ZAKAZNIK.PRIJMENI
FROM ZAKAZNIK
JOIN OBJEDNAVKA ON OBJEDNAVKA.ZAKAZNIK_ID = ZAKAZNIK.ID
WHERE OBJEDNAVKA.CENA > 500;

Transakce

Transakce jsou skupiny příkazů (SELECT, INSERT, ...), která se buď provede celá, nebo vůbec. To má velkou výhodu v tom, že pokud některý z příkazů vyvolá chybu, tak se databáze vrátí do původního stavu, my můžeme příkaz opravit a celou transakci spustit znovu.

O transakcích se ale bavíme především proto, že je důležité je ukončit, a to buď příkazem COMMIT nebo ROLLBACK. COMMIT uloží námi provedené změny trvale do databáze, takže je uvidíme i v budoucích transakcích. ROLLBACK vrátí databázi do původního stavu, což se může hodit v případě, že jsme provedli jiné změny, než jsme chtěli.

-- vložení dat
INSERT INTO ROBOT (ID, NAME, TYPE) VALUES(1, "Jim", "AGGRESSIVE");
-- v této chvíli ještě nejsou data trvale uložena

-- uložení dat
COMMIT;

SQLite

Celé povídání o databázích by nemělo moc smysl, pokud bychom si neukázali, jak je využít z prostředí Pythonu. Jak jsme už zmínili, existují různé databázové systémy, my se ale zaměříme na jeden z nejjednodušších na "rozjetí", a to SQLite.

Tento systém ukládá celou databázi do jednoho binárního souboru. Můžeme si na něm jednoduše vyzkoušet jednotlivé SQL příkazy, a to prostřednictvím Python balíčku sqlite3. Ukažme si využití tohoto balíčku na příkladech.

import sqlite3

# Připojíme se k databázi (v souboru)
connection = sqlite3.connect('pyladies_example_1.db')

# Získáme instanci třídy `Cursor`, pomocí které bude do databáze posílat příkazy
cursor = connection.cursor()

# Pokud tabulka  existuje, tak ji odstraníme,
# abychom mohli skript spouštět opakovaně
cursor.execute("""DROP TABLE IF EXISTS ROBOT""")

# Vytvoříme jednoduchou tabulku
cursor.execute("""CREATE TABLE ROBOT (NAME TEXT, TYPE TEXT)""")

# Vložíme do tabulky data
cursor.execute("""
    INSERT INTO ROBOT (NAME, TYPE)
    VALUES ("JIM", "DEFENSIVE"), ("JACK", "OFFENSIVE")
""")

# Dotážeme se na všechny roboty, výsledky vypíšeme
robots = cursor.execute("SELECT * FROM ROBOT")
for robot in robots:
    print(robot)

# Uložíme změny a uzavřeme spojení
connection.commit()
connection.close()
# Složitejší příklad, který pracuje s primárními a cizími klíči
# a se spojováním tabulek

import sqlite3

# Připojíme se k databázi (v souboru)
connection = sqlite3.connect('pyladies_example_2.db')

# Získáme instanci třídy `Cursor`, pomocí které bude do databáze posílat příkazy
cursor = connection.cursor()

# Pokud tabulky  existují, tak ji odstraníme,
# abychom mohli skript spouštět opakovaně
cursor.execute("""DROP TABLE IF EXISTS ROBOT""")
cursor.execute("""DROP TABLE IF EXISTS BATTLE""")

# Vytvoříme tabulku s roboty a tabulky s výsledky bitev
cursor.execute("""
-- u jednotlivých roborů si ukládáme ID, jméno a typ
CREATE TABLE ROBOT (
    ROBOT_ID INT PRIMARY KEY,
    NAME TEXT,
    TYPE TEXT)
""")

cursor.execute("""
-- bitva se skládá z ID bitvy, ID vítěze a poraženého (odpovídají ID v tabulce ROBOT)
-- a z bodů pro vítěze a poraženého
CREATE TABLE BATTLE (
    BATTLE_ID INT PRIMARY KEY,
    WINNER_ID INT,
    LOSER_ID INT,
    WINNER_POINTS INT,
    LOSER_POINTS INT,
    FOREIGN KEY(WINNER_ID) REFERENCES ROBOT(ROBOT_ID),
    FOREIGN KEY(LOSER_ID) REFERENCES ROBOT(ROBOT_ID)
    )
""")

# Vložíme do tabulkek data
cursor.execute("""
    INSERT INTO ROBOT (ROBOT_ID, NAME, TYPE) VALUES
    (1, "JIM", "DEFENSIVE"), (2, "JACK", "OFFENSIVE"), (3, "JIMMY", "OFFESIVE")
""")

cursor.execute("""
    INSERT INTO BATTLE (BATTLE_ID, WINNER_ID, LOSER_ID, WINNER_POINTS, LOSER_POINTS) VALUES
    (1, 1, 2, 10, 8), -- robot 1 porazil robota 2 se skóre 10:8 (v bitvě 1)
    (2, 2, 1, 6, 9),
    (3, 2, 3, 10, 9),
    (4, 1, 3, 5, 4),
    (5, 3, 2, 2, 0),
    (6, 1, 2, 9, 6)
""")

# Dotážeme se na výsledky bitev, které vyhrál robot se jménem "JIM"
scores = cursor.execute("""
    SELECT BATTLE.WINNER_POINTS, BATTLE.LOSER_POINTS
    FROM BATTLE
    JOIN ROBOT ON ROBOT.ROBOT_ID = BATTLE.WINNER_ID
    WHERE ROBOT.NAME = "JIM"
""")

for score in scores:
    print(score)

# Uložíme změny a uzavřeme spojení
connection.commit()
connection.close()

ORM

V Pythonu jsme se naučili data a logiku sdružovat do tříd. V databázích se data sdružují do tabulek. O propojení těchto konceptů se stará ORM - Objektově Relační Mapování. Pomocí ORM Frameworku (v Pythonu např. SQLAlchemy) vytváříme Python třídy, pro které existují odpovídající tabulky v databázi.

Například Python třída Kocka bude mít odpovídající tabulku KOCKA. Atributy třídy (Vek, Barva) budou v databázi existovat jako sloupce. Jednotlivé řádky tabulky bude možné načíst do aplikace jako instance třídy Kocka. Jednotlivé kočky samozřejmě bude možné upravovat, mazat, nebo vytvářet nové.

Ukázku ORM najdete na Wikipedii

{
  "data": {
    "sessionMaterial": {
      "id": "session-material:2019/brno-jaro-2019-ut:github-api:2",
      "title": "Úvod do Relačních databází",
      "html": "\n          \n    \n\n    <h1>Rela&#x10D;n&#xED; Datab&#xE1;ze</h1>\n<p>V&#x11B;t&#x161;ina aplikac&#xED;, zejm&#xE9;na t&#x11B;ch webov&#xFD;ch, pot&#x159;ebuje manipulovat s daty.\nM&#x16F;&#x17E;e se jednat t&#x159;eba o spr&#xE1;vu objedn&#xE1;vek, produkt&#x16F; na eshopu nebo bankovn&#xED;ch transakc&#xED;.</p>\n<p>Vzhledem k tomu, &#x17E;e datab&#xE1;ze jsou velice komplexn&#xED; t&#xE9;ma, tak si v t&#xE9;to lekci\nprojedeme jen z&#xE1;klady. Pokud v&#xE1;s ale datab&#xE1;ze zaujmou, tak je dobr&#xE9; se pod&#xED;vat\npo dal&#x161;&#xED;ch materi&#xE1;lech, nap&#x159;&#xED;klad na <a href=\"https://www.w3schools.com/sql/\">W3Schools</a>.</p>\n<p>Nad daty prov&#xE1;d&#xED;me &#x10D;ty&#x159;i druhy operac&#xED; - vytv&#xE1;&#x159;en&#xED;, &#x10D;ten&#xED;, &#xFA;pravu a maz&#xE1;n&#xED;.\nTyto operace se sdru&#x17E;uj&#xED; do zkratky <strong>CRUD</strong> (Create, Read, Update, Delete).</p>\n<p>Existuj&#xED; r&#x16F;zn&#xE9; mo&#x17E;nosti, kam data ukl&#xE1;dat. Mohli bychom nap&#x159;&#xED;klad v&#x161;e zapisovat\ndo jednoho souboru. Brzy bychom ale zjistili, &#x17E;e se jedn&#xE1; o velice neefektivn&#xED;\nzp&#x16F;sob - operace nad daty by s rostouc&#xED;m po&#x10D;tem z&#xE1;znam&#x16F; za&#x10D;aly b&#xFD;t pomal&#xE9;.\nV t&#x11B;chto situac&#xED;ch nastupuj&#xED; na sc&#xE9;nu datab&#xE1;ze (resp. datab&#xE1;zov&#xE9; syst&#xE9;my).</p>\n<p>Jedn&#xE1; se o vysoce sofistikovan&#xE1; &#x159;e&#x161;en&#xED; r&#x16F;zn&#xFD;ch v&#xFD;robc&#x16F; (zm&#xED;nit m&#x16F;&#x17E;eme t&#x159;eba\n<em>Oracle</em> nebo <em>MySQL</em>). V&#xFD;hodou je, &#x17E;e tyto syst&#xE9;my maj&#xED; spole&#x10D;n&#xFD; zp&#x16F;sob,\njak&#xFD;m se s nimi komunikuje (API) - prost&#x159;ednictv&#xED;m jazyka <strong>SQL</strong>. Nemus&#xED; n&#xE1;s tedy\nzaj&#xED;mat, jak datab&#xE1;ze funguje uvnit&#x159;.</p>\n<p>Z&#xE1;kladem rela&#x10D;n&#xED;ch datab&#xE1;z&#xED; jsou <strong>tabulky</strong>. M&#x16F;&#x17E;eme si je p&#x159;edstavit jako jeden\nlist se&#x161;itu MS Excel (cel&#xFD; se&#x161;it by pak odpov&#xED;dal datab&#xE1;zi). Jednotliv&#xE9; &#x159;&#xE1;dky\ntabulky jsou <strong>z&#xE1;znamy</strong>. Ty se skl&#xE1;daj&#xED; z n&#x11B;kolika <strong>atribut&#x16F;</strong> (sloupc&#x16F;).\n&#x158;&#xE1;dky a sloupce odpov&#xED;daj&#xED; Excelov&#xFD;m &#x159;&#xE1;dk&#x16F;m a sloupc&#x16F;m.</p>\n<p>M&#x16F;&#x17E;eme m&#xED;t nap&#x159;&#xED;klad tabulku <code>OBJEDNAVKA</code>. Bude tvo&#x159;ena sloupci <code>ID_OBJEDNAVKY</code>,\n<code>ID_ZAKAZNIKA</code>, <code>DATUM</code>, <code>CENA</code>. Jednotliv&#xE9; z&#xE1;znamy p&#x159;edstavuj&#xED; jednotliv&#xE9;\nobjedn&#xE1;vky - v&#xED;me tedy kdy si kdo ud&#x11B;lal objedn&#xE1;vku, a kolik za ni zaplatil.</p>\n<h2>SQL</h2>\n<p>SQL (Structured Querying Language - Strukturovan&#xFD; dotazovac&#xED; jazyk) n&#xE1;m umo&#x17E;&#x148;uje\nkomunikovat s datab&#xE1;z&#xED;. V&#xFD;robci jednoliv&#xFD;ch datab&#xE1;z&#xED; obvykle jazyk v n&#x11B;kter&#xFD;ch\noblastech roz&#x161;i&#x159;uj&#xED;, z&#xE1;klad je ale spole&#x10D;n&#xFD; a standardzivan&#xFD;. Krom&#x11B; pr&#xE1;ci s daty\n(CRUD) se jazyk pou&#x17E;&#xED;v&#xE1; pro vytv&#xE1;&#x159;en&#xED; tabulek a dal&#x161;&#xED;ch objekt&#x16F;, pro spr&#xE1;vu\nu&#x17E;ivatel&#x16F; datab&#xE1;ze apod.</p>\n<p>SQL p&#x159;&#xED;kazy mohou b&#xFD;t do datab&#xE1;ze pos&#xED;l&#xE1;ny z webov&#xE9; aplikace (Python, Javascript, ...),\nz termin&#xE1;lu, nebo t&#x159;eba z aplikace p&#x159;&#xED;mo ur&#x10D;en&#xE9; pro spr&#xE1;vu datab&#xE1;ze.\nJe zvykem jednotliv&#xE9; p&#x159;&#xED;kazy jazyka ps&#xE1;t <code>VELK&#xDD;MI P&#xCD;SMENY</code>. P&#x159;&#xED;kazy odd&#x11B;lujeme\nst&#x159;edn&#xED;kem <code>;</code>. Jedno&#x159;&#xE1;dkov&#xE9; koment&#xE1;&#x159;e uvozujeme dv&#x11B;ma spojovn&#xED;ky <code>--</code>\na v&#xED;ce&#x159;&#xE1;dkov&#xE9; koment&#xE1;&#x159;e p&#xED;&#x161;eme mezi <code>/*</code> a <code>*/</code>.</p>\n<p>Poj&#x10F;me se pod&#xED;vat na n&#x11B;kter&#xE9; z p&#x159;&#xED;kaz&#x16F;, kter&#xE9; SQL podporuje.</p>\n<h3>Tabulky</h3>\n<p>Pro vytvo&#x159;en&#xED; tabulky pou&#x17E;ijeme p&#x159;&#xED;kaz <code>CREATE TABLE</code>, n&#xE1;sledovan&#xFD; jm&#xE9;nem tabulky\na definic&#xED; jednotliv&#xFD;ch sloupc&#x16F;. U sloupc&#x16F; definuje jm&#xE9;no, typ a p&#x159;&#xED;padn&#x11B; dal&#x161;&#xED;\nvlastnosti.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"cm\">/* Vytvo&#x159;&#xED; tabulku ROBOT se sloupci ID, NAME a TYPE.</span>\n<span class=\"cm\">   ID je cel&#xE9; &#x10D;&#xED;slo, NAME a TYPE jsou &#x159;et&#x11B;zce.</span>\n<span class=\"cm\">*/</span>\n<span class=\"k\">CREATE</span> <span class=\"k\">TABLE</span> <span class=\"n\">ROBOT</span> <span class=\"p\">(</span>\n    <span class=\"n\">ID</span>      <span class=\"nb\">INT</span>     <span class=\"k\">PRIMARY</span> <span class=\"k\">KEY</span><span class=\"p\">,</span>\n    <span class=\"n\">NAME</span>    <span class=\"nb\">TEXT</span><span class=\"p\">,</span>\n    <span class=\"k\">TYPE</span>    <span class=\"nb\">TEXT</span>\n<span class=\"p\">)</span>\n</pre></div><p>V&#xFD;znam <code>PRIMARY_KEY</code> si vysv&#x11B;tl&#xED;me pozd&#x11B;ji. Pokud bychom cht&#x11B;li tabulku smazat,\ntak pou&#x17E;ijeme <code>DROP TABLE JMENO_TABULKY</code>. Jen pozor - spolu s tabulkou se\n<strong>sma&#x17E;ou v&#x161;echny z&#xE1;znamy</strong> v n&#xED; obsa&#x17E;en&#xE9;.</p>\n<h3>INSERT</h3>\n<p>Jakmile m&#xE1;me vytvo&#x159;enou tabulku, m&#x16F;&#x17E;eme do n&#xED; vkl&#xE1;dat z&#xE1;znamy. D&#x11B;l&#xE1;me tak\npomoc&#xED; p&#x159;&#xED;kazu <code>INSERT</code>. Uvedeme jm&#xE9;no tabulky a pak hodnoty, p&#x159;edstavuj&#xED;c&#xED;\nz&#xE1;znam (nebo z&#xE1;znamy), kter&#xE9; se maj&#xED; vlo&#x17E;it.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"c1\">-- Vlo&#x17E;&#xED; do tabulky ROBOT nov&#xE9;ho Robota s ID 1, jm&#xE9;nem Jim a typem AGGRESIVE</span>\n<span class=\"k\">INSERT</span> <span class=\"k\">INTO</span> <span class=\"n\">ROBOT</span> <span class=\"p\">(</span><span class=\"n\">ID</span><span class=\"p\">,</span> <span class=\"n\">NAME</span><span class=\"p\">,</span> <span class=\"k\">TYPE</span><span class=\"p\">)</span> <span class=\"k\">VALUES</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"ss\">&quot;Jim&quot;</span><span class=\"p\">,</span> <span class=\"ss\">&quot;AGGRESSIVE&quot;</span><span class=\"p\">);</span>\n\n<span class=\"c1\">-- Vlo&#x17E;&#xED; do tabulky ROBOT dal&#x161;&#xED; dva Roboty</span>\n<span class=\"k\">INSERT</span> <span class=\"k\">INTO</span> <span class=\"n\">ROBOT</span> <span class=\"p\">(</span><span class=\"n\">ID</span><span class=\"p\">,</span> <span class=\"n\">NAME</span><span class=\"p\">,</span> <span class=\"k\">TYPE</span><span class=\"p\">)</span> <span class=\"k\">VALUES</span> <span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"ss\">&quot;John&quot;</span><span class=\"p\">,</span> <span class=\"ss\">&quot;DEFENSIVE&quot;</span><span class=\"p\">),(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"ss\">&quot;Jack&quot;</span><span class=\"p\">,</span> <span class=\"ss\">&quot;DEFENSIVE&quot;</span><span class=\"p\">);</span>\n</pre></div><h3>SELECT</h3>\n<p>Kdy&#x17E; u&#x17E; m&#xE1;me i n&#x11B;jak&#xE9; zazn&#xE1;my, tak je dobr&#xE9; m&#xED;t zp&#x16F;sob, jak je &#x10D;&#xED;st. Slou&#x17E;&#xED;\nk tomu mocn&#xFD; p&#x159;&#xED;kaz <code>SELECT</code>, kter&#xFD; v nejz&#xE1;kladn&#x11B;j&#x161;&#xED; podob&#x11B; o&#x10D;ek&#xE1;v&#xE1; seznam sloupc&#x16F;,\nkter&#xFD; se m&#xE1; pro jednotliv&#xE9; z&#xE1;znamy vypsat, a jm&#xE9;no tabulky, ze kter&#xE9; se maj&#xED;\ndata &#x10D;&#xED;st. Seznam sloupc&#x16F; m&#x16F;&#x17E;eme nahradit hv&#x11B;zdi&#x10D;kou <code>*</code>, pokud chceme vypsat\nhodnoty v&#x161;ech sloupc&#x16F;.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"c1\">-- vyp&#xED;&#x161;e hodnoty v&#x161;ech sloupc&#x16F; pro v&#x161;echny roboty</span>\n<span class=\"k\">SELECT</span> <span class=\"o\">*</span> <span class=\"k\">FROM</span> <span class=\"n\">ROBOT</span><span class=\"p\">;</span>\n\n<span class=\"c1\">-- vyp&#xED;&#x161;e jen jm&#xE9;na v&#x161;ech robot&#x16F;</span>\n<span class=\"k\">SELECT</span> <span class=\"n\">NAME</span> <span class=\"k\">FROM</span> <span class=\"n\">ROBOT</span><span class=\"p\">;</span>\n</pre></div><p>P&#x159;&#xED;kaz <code>SELECT</code> podporuje t&#x159;eba tak&#xE9; filtrov&#xE1;n&#xED; dat (uk&#xE1;&#x17E;eme si pozd&#x11B;ji),\n&#x159;azen&#xED; (<code>ORDER BY</code>) a seskupov&#xE1;n&#xED; dat (pr&#x16F;m&#x11B;r - <code>AVG</code>, suma - <code>SUM</code>, ...)</p>\n<h3>UPDATE</h3>\n<p>V p&#x159;&#xED;pad&#x11B;, &#x17E;e chceme data upravit (nap&#x159;&#xED;klad zm&#x11B;nit jm&#xE9;no robota),\ntak pou&#x17E;ijeme p&#x159;&#xED;kaz <code>UPDATE</code>. I ten o&#x10D;ek&#xE1;v&#xE1; jm&#xE9;no tabulky, jej&#xED;&#x17E; z&#xE1;znamy se\nmaj&#xED; upravit. Krom&#x11B; toho tak&#xE9; zad&#xE1;me nov&#xE9; hodnoty pro jednotliv&#xE9; sloupce.\nHodnoty sloupc&#x16F;, kter&#xE9; neuvedeme, z&#x16F;stanou nezm&#x11B;n&#x11B;n&#xE9;.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"c1\">-- nastav&#xED; v&#x161;em robot&#x16F;m typ na AGGRESSIVE</span>\n<span class=\"k\">UPDATE</span> <span class=\"n\">ROBOT</span> <span class=\"k\">SET</span> <span class=\"k\">TYPE</span> <span class=\"o\">=</span> <span class=\"ss\">&quot;AGGRESSIVE&quot;</span><span class=\"p\">;</span>\n</pre></div><h3>DELETE</h3>\n<p>A kone&#x10D;n&#x11B; posledn&#xED; oprac&#xED; v CRUD je maz&#xE1;n&#xED;. V SQL se z&#xE1;znamy ma&#x17E;ou pomoc&#xED; p&#x159;&#xED;kazu\n<code>DELETE</code>. I zde, stejn&#x11B; jako u ostatn&#xED;ch CRUD p&#x159;&#xED;kaz&#x16F;, uv&#xE1;d&#xED;me jm&#xE9;no tabulky.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"c1\">-- sma&#x17E;e v&#x161;echny roboty</span>\n<span class=\"k\">DELETE</span> <span class=\"k\">FROM</span> <span class=\"n\">ROBOT</span><span class=\"p\">;</span>\n</pre></div><h3>WHERE</h3>\n<p>Nejsp&#xED;&#x161; v&#xE1;s napadalo, &#x17E;e pokud bychom v&#x17E;dy &#x10D;etli, upravovali nebo mazali v&#x161;echna\ndata v tabulce, tak by syst&#xE9;m nebyl moc dob&#x159;e pou&#x17E;iteln&#xFD;. Na&#x161;t&#x11B;st&#xED; ale m&#x16F;&#x17E;eme\npomoc&#xED; p&#x159;&#xED;kazu <code>WHERE</code> ovlivnit, nad jak&#xFD;mi z&#xE1;znamy se bude operace prov&#xE1;d&#x11B;t.</p>\n<p>Za <code>WHERE</code> se p&#xED;&#x161;&#xED; podm&#xED;nky (spojovan&#xE9; pomoc&#xED; <code>AND</code> nebo <code>OR</code>), kter&#xE9; mus&#xED;\nplatit, aby se z&#xE1;znam p&#x159;idal do mno&#x17E;iny, nad kterou se bude operace\nprov&#xE1;d&#x11B;t. V podm&#xED;nk&#xE1;ch je mo&#x17E;n&#xE9; pou&#x17E;&#xED;t r&#x16F;zn&#xE9; oper&#xE1;tory:</p>\n<ul>\n<li>rovnost: <code>WHERE SLOUPEC = HODNOTA</code></li>\n<li>nerovnost: <code>WHERE SLOUPEC &gt; HODNOTA</code> (<code>&gt;</code>, <code>&lt;</code>, <code>&lt;&gt;</code>, ...)</li>\n<li>jedna z hodnot: <code>WHERE SLOUPEC IN (HODNOTA_1, HODNOTA_2)</code></li>\n<li>pod&#x159;et&#x11B;zec: <code>WHERE SLOUPEC LIKE %HODNOTA%</code></li>\n</ul>\n<div class=\"highlight\"><pre><span></span><span class=\"c1\">-- vyp&#xED;&#x161;e v&#x161;echny &#x159;&#xE1;dky o robotech, kter&#xE9; maj&#xED; typ AGGRESSIVE</span>\n<span class=\"k\">SELECT</span> <span class=\"o\">*</span> <span class=\"k\">FROM</span> <span class=\"n\">ROBOT</span> <span class=\"k\">WHERE</span> <span class=\"k\">TYPE</span> <span class=\"o\">=</span> <span class=\"ss\">&quot;AGGRESSIVE&quot;</span><span class=\"p\">;</span>\n\n<span class=\"c1\">-- p&#x159;ejmenuje roboty, jejich&#x17E; jm&#xE9;na za&#x10D;&#xED;naj&#xED; na J, na Jimmy</span>\n<span class=\"k\">UPDATE</span> <span class=\"n\">ROBOT</span> <span class=\"k\">SET</span> <span class=\"n\">NAME</span> <span class=\"o\">=</span> <span class=\"ss\">&quot;Jimmy&quot;</span> <span class=\"k\">WHERE</span> <span class=\"n\">NAME</span> <span class=\"k\">LIKE</span> <span class=\"ss\">&quot;J%&quot;</span><span class=\"p\">;</span>\n\n<span class=\"c1\">-- sma&#x17E;e robota s ID v&#x11B;t&#x161;&#xED;m ne&#x17E; 1</span>\n<span class=\"k\">DELETE</span> <span class=\"k\">FROM</span> <span class=\"n\">ROBOT</span> <span class=\"k\">WHERE</span> <span class=\"n\">ID</span> <span class=\"o\">&gt;</span> <span class=\"mi\">1</span><span class=\"p\">;</span>\n</pre></div><h2>Prim&#xE1;rn&#xED; kl&#xED;&#x10D;e</h2>\n<p>Ka&#x17E;d&#xE1; tabulka by m&#x11B;la m&#xED;t soupec, kter&#xFD; jednozna&#x10D;n&#x11B; identifikuje jednotliv&#xE9; &#x159;&#xE1;dky.\nVe sloupci mus&#xED; b&#xFD;t unik&#xE1;tn&#xED; hodnoty. M&#x16F;&#x17E;e se jednat o um&#x11B;le vytvo&#x159;en&#xE9; &#x10D;&#xED;slo\n(nej&#x10D;ast&#x11B;ji naz&#xFD;van&#xE9; <code>ID</code>), nebo m&#x16F;&#x17E;e j&#xED;t o unik&#xE1;tn&#xED; identifik&#xE1;tor z re&#xE1;ln&#xE9;ho\nsv&#x11B;ta. Pozor ale na to, &#x17E;e ne ka&#x17E;d&#xFD; na prvn&#xED; pohled unik&#xE1;tn&#xED; identifik&#xE1;tor je\n<em>skute&#x10D;n&#x11B;</em> unik&#xE1;tn&#xED; - je nap&#x159;&#xED;klad mo&#x17E;n&#xE9;, aby dv&#x11B; osoby m&#x11B;ly stejn&#xE9; rodn&#xE9; &#x10D;&#xED;slo.\nJe tedy obecn&#x11B; lep&#x161;&#xED; pou&#x17E;&#xED;vat um&#x11B;le vytvo&#x159;en&#xE9; prim&#xE1;rn&#xED; kl&#xED;&#x10D;e.</p>\n<p>Prim&#xE1;rn&#xED; kl&#xED;&#x10D;e se pou&#x17E;&#xED;vaj&#xED; proto, &#x17E;e zrychluj&#xED; operace nad daty (rychle se podle\nnich vyhled&#xE1;v&#xE1;) a tak&#xE9; proto, &#x17E;e sni&#x17E;uj&#xED; riziko duplicitn&#xED;ch dat v datab&#xE1;zi.\nP&#x159;i vytv&#xE1;&#x159;en&#xED; tabulky zad&#xE1;me u sloupce, kter&#xFD; m&#xE1; b&#xFD;t prim&#xE1;rn&#xED;m kl&#xED;&#x10D;em, vlastnost\n<code>PRIMARY KEY</code>.</p>\n<h2>Ciz&#xED; kl&#xED;&#x10D;e</h2>\n<p>Ciz&#xED; kl&#xED;&#x10D;e - <code>FOREIGN KEY</code> - se vyu&#x17E;&#xED;vaj&#xED; pro zachycen&#xED; vazby mezi tabulkami.\nV dce&#x159;in&#xE9; tabulce m&#xE1;me sloupec p&#x159;edstavuj&#xED;c&#xED; ciz&#xED; kl&#xED;&#x10D;, jeho&#x17E; hodnoty se\nodkazuj&#xED; na prim&#xE1;rn&#xED; kl&#xED;&#x10D; jin&#xE9; tabulky.</p>\n<p>Nap&#x159;&#xED;klad tabulka <code>OBJEDNAVKA</code> m&#xE1; ciz&#xED; kl&#xED;&#x10D; <code>ID_ZAKAZNIKA</code>. Tento ciz&#xED; kl&#xED;&#x10D;\nse odkazuje na prim&#xE1;rn&#xED; kl&#xED;&#x10D; tabulky <code>ZAKAZNIK</code>. T&#xED;m zaru&#x10D;&#xED;me, &#x17E;e ka&#x17E;d&#xE1; objedn&#xE1;vka\nmus&#xED; b&#xFD;t &quot;napojen&#xE1;&quot; na existuj&#xED;c&#xED;ho z&#xE1;kazn&#xED;ka.</p>\n<p><span class=\"figure\"><a href=\"/2019/brno-jaro-2019-ut/beginners/database/static/fk.png\"><img src=\"/2019/brno-jaro-2019-ut/beginners/database/static/fk.png\" alt=\"Ciz&#xED; kl&#xED;&#x10D;e\"></a></span></p>\n<p><a href=\"https://cdn-images-1.medium.com/max/1600/1*yW_ha3z8Mp6fUn9m6qWwNw.png\">zdroj obr&#xE1;zku</a></p>\n<h2>Spojov&#xE1;n&#xED; tabulek</h2>\n<p>&#x10C;asto pot&#x159;ebujeme v jednom dotazu &#x10D;&#xED;st data z v&#xED;ce tabulek. Pou&#x17E;&#xED;v&#xE1;me k tomu\np&#x159;&#xED;kaz <code>JOIN</code>, kter&#xFD; je sou&#x10D;&#xE1;st&#xED; p&#x159;&#xED;kazu <code>SELECT</code>. V z&#xE1;kladn&#xED; verzi vezme\n<code>JOIN</code> z&#xE1;znamy z jedn&#xE9; tabulky a p&#x159;ipoj&#xED; k nim odpov&#xED;daj&#xED;c&#xED; z&#xE1;znamy z druh&#xE9;\ntabulky. Na takto nov&#x11B; vznikl&#xFD; &#x159;&#xE1;dek je mo&#x17E;n&#xE9; ud&#x11B;lat <code>JOIN</code> s dal&#x161;&#xED; tabulkou.</p>\n<p>To, co pova&#x17E;ujeme za &quot;odpov&#xED;daj&#xED;c&#xED; z&#xE1;znam&quot; zap&#xED;&#x161;eme jako sou&#x10D;&#xE1;st <code>JOIN</code>\n(za kl&#xED;&#x10D;ov&#xE9; slovo <code>ON</code>). Nejd&#x159;&#xED;ve ale mus&#xED;me zadat jm&#xE9;no tabulky,\nkterou chceme p&#x159;ipojit.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"c1\">-- vyp&#xED;&#x161;e jm&#xE9;na a p&#x159;&#xED;jmen&#xED; z&#xE1;kazn&#xED;k&#x16F;, kte&#x159;&#xED; ud&#x11B;lali objedn&#xE1;vku za v&#xED;ce ne&#x17E; 500 K&#x10D;</span>\n\n<span class=\"k\">SELECT</span> <span class=\"n\">ZAKAZNIK</span><span class=\"p\">.</span><span class=\"n\">JMENO</span><span class=\"p\">,</span> <span class=\"n\">ZAKAZNIK</span><span class=\"p\">.</span><span class=\"n\">PRIJMENI</span>\n<span class=\"k\">FROM</span> <span class=\"n\">ZAKAZNIK</span>\n<span class=\"k\">JOIN</span> <span class=\"n\">OBJEDNAVKA</span> <span class=\"k\">ON</span> <span class=\"n\">OBJEDNAVKA</span><span class=\"p\">.</span><span class=\"n\">ZAKAZNIK_ID</span> <span class=\"o\">=</span> <span class=\"n\">ZAKAZNIK</span><span class=\"p\">.</span><span class=\"n\">ID</span>\n<span class=\"k\">WHERE</span> <span class=\"n\">OBJEDNAVKA</span><span class=\"p\">.</span><span class=\"n\">CENA</span> <span class=\"o\">&gt;</span> <span class=\"mi\">500</span><span class=\"p\">;</span>\n</pre></div><h2>Transakce</h2>\n<p>Transakce jsou skupiny p&#x159;&#xED;kaz&#x16F; (<code>SELECT</code>, <code>INSERT</code>, ...), kter&#xE1; se bu&#x10F; provede\ncel&#xE1;, nebo v&#x16F;bec. To m&#xE1; velkou v&#xFD;hodu v tom, &#x17E;e pokud n&#x11B;kter&#xFD; z p&#x159;&#xED;kaz&#x16F; vyvol&#xE1;\nchybu, tak se datab&#xE1;ze vr&#xE1;t&#xED; do p&#x16F;vodn&#xED;ho stavu, my m&#x16F;&#x17E;eme p&#x159;&#xED;kaz opravit\na celou transakci spustit znovu.</p>\n<p>O transakc&#xED;ch se ale bav&#xED;me p&#x159;edev&#x161;&#xED;m proto, &#x17E;e je d&#x16F;le&#x17E;it&#xE9; je <strong>ukon&#x10D;it</strong>,\na to bu&#x10F; p&#x159;&#xED;kazem <code>COMMIT</code> nebo <code>ROLLBACK</code>. <code>COMMIT</code> ulo&#x17E;&#xED; n&#xE1;mi proveden&#xE9;\nzm&#x11B;ny trvale do datab&#xE1;ze, tak&#x17E;e je uvid&#xED;me i v budouc&#xED;ch transakc&#xED;ch.\n<code>ROLLBACK</code> vr&#xE1;t&#xED; datab&#xE1;zi do p&#x16F;vodn&#xED;ho stavu, co&#x17E; se m&#x16F;&#x17E;e hodit v p&#x159;&#xED;pad&#x11B;,\n&#x17E;e jsme provedli jin&#xE9; zm&#x11B;ny, ne&#x17E; jsme cht&#x11B;li.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"c1\">-- vlo&#x17E;en&#xED; dat</span>\n<span class=\"k\">INSERT</span> <span class=\"k\">INTO</span> <span class=\"n\">ROBOT</span> <span class=\"p\">(</span><span class=\"n\">ID</span><span class=\"p\">,</span> <span class=\"n\">NAME</span><span class=\"p\">,</span> <span class=\"k\">TYPE</span><span class=\"p\">)</span> <span class=\"k\">VALUES</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"ss\">&quot;Jim&quot;</span><span class=\"p\">,</span> <span class=\"ss\">&quot;AGGRESSIVE&quot;</span><span class=\"p\">);</span>\n<span class=\"c1\">-- v t&#xE9;to chv&#xED;li je&#x161;t&#x11B; nejsou data trvale ulo&#x17E;ena</span>\n\n<span class=\"c1\">-- ulo&#x17E;en&#xED; dat</span>\n<span class=\"k\">COMMIT</span><span class=\"p\">;</span>\n</pre></div><h2>SQLite</h2>\n<p>Cel&#xE9; pov&#xED;d&#xE1;n&#xED; o datab&#xE1;z&#xED;ch by nem&#x11B;lo moc smysl, pokud bychom si neuk&#xE1;zali,\njak je vyu&#x17E;&#xED;t z prost&#x159;ed&#xED; Pythonu. Jak jsme u&#x17E; zm&#xED;nili, existuj&#xED; r&#x16F;zn&#xE9; datab&#xE1;zov&#xE9;\nsyst&#xE9;my, my se ale zam&#x11B;&#x159;&#xED;me na jeden z nejjednodu&#x161;&#x161;&#xED;ch na &quot;rozjet&#xED;&quot;, a to <strong>SQLite</strong>.</p>\n<p>Tento syst&#xE9;m ukl&#xE1;d&#xE1; celou datab&#xE1;zi do jednoho bin&#xE1;rn&#xED;ho souboru.\nM&#x16F;&#x17E;eme si na n&#x11B;m jednodu&#x161;e vyzkou&#x161;et jednotliv&#xE9; SQL p&#x159;&#xED;kazy,\na to prost&#x159;ednictv&#xED;m Python bal&#xED;&#x10D;ku <code>sqlite3</code>. Uka&#x17E;me si vyu&#x17E;it&#xED; tohoto bal&#xED;&#x10D;ku\nna p&#x159;&#xED;kladech.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">import</span> <span class=\"n\">sqlite3</span>\n\n<span class=\"o\">#</span> <span class=\"n\">P&#x159;ipoj&#xED;me</span> <span class=\"n\">se</span> <span class=\"n\">k</span> <span class=\"n\">datab&#xE1;zi</span> <span class=\"p\">(</span><span class=\"n\">v</span> <span class=\"n\">souboru</span><span class=\"p\">)</span>\n<span class=\"k\">connection</span> <span class=\"o\">=</span> <span class=\"n\">sqlite3</span><span class=\"p\">.</span><span class=\"k\">connect</span><span class=\"p\">(</span><span class=\"s1\">&apos;pyladies_example_1.db&apos;</span><span class=\"p\">)</span>\n\n<span class=\"o\">#</span> <span class=\"n\">Z&#xED;sk&#xE1;me</span> <span class=\"n\">instanci</span> <span class=\"n\">t&#x159;&#xED;dy</span> <span class=\"o\">`</span><span class=\"k\">Cursor</span><span class=\"o\">`</span><span class=\"p\">,</span> <span class=\"n\">pomoc&#xED;</span> <span class=\"n\">kter&#xE9;</span> <span class=\"n\">bude</span> <span class=\"k\">do</span> <span class=\"n\">datab&#xE1;ze</span> <span class=\"n\">pos&#xED;lat</span> <span class=\"n\">p&#x159;&#xED;kazy</span>\n<span class=\"k\">cursor</span> <span class=\"o\">=</span> <span class=\"k\">connection</span><span class=\"p\">.</span><span class=\"k\">cursor</span><span class=\"p\">()</span>\n\n<span class=\"o\">#</span> <span class=\"n\">Pokud</span> <span class=\"n\">tabulka</span> <span class=\"n\">u&#x17E;</span> <span class=\"n\">existuje</span><span class=\"p\">,</span> <span class=\"n\">tak</span> <span class=\"n\">ji</span> <span class=\"n\">odstran&#xED;me</span><span class=\"p\">,</span>\n<span class=\"o\">#</span> <span class=\"n\">abychom</span> <span class=\"n\">mohli</span> <span class=\"n\">skript</span> <span class=\"n\">spou&#x161;t&#x11B;t</span> <span class=\"n\">opakovan&#x11B;</span>\n<span class=\"k\">cursor</span><span class=\"p\">.</span><span class=\"k\">execute</span><span class=\"p\">(</span><span class=\"ss\">&quot;&quot;&quot;DROP TABLE IF EXISTS ROBOT&quot;&quot;&quot;</span><span class=\"p\">)</span>\n\n<span class=\"o\">#</span> <span class=\"n\">Vytvo&#x159;&#xED;me</span> <span class=\"n\">jednoduchou</span> <span class=\"n\">tabulku</span>\n<span class=\"k\">cursor</span><span class=\"p\">.</span><span class=\"k\">execute</span><span class=\"p\">(</span><span class=\"ss\">&quot;&quot;&quot;CREATE TABLE ROBOT (NAME TEXT, TYPE TEXT)&quot;&quot;&quot;</span><span class=\"p\">)</span>\n\n<span class=\"o\">#</span> <span class=\"n\">Vlo&#x17E;&#xED;me</span> <span class=\"k\">do</span> <span class=\"n\">tabulky</span> <span class=\"k\">data</span>\n<span class=\"k\">cursor</span><span class=\"p\">.</span><span class=\"k\">execute</span><span class=\"p\">(</span><span class=\"ss\">&quot;&quot;&quot;</span>\n<span class=\"ss\">    INSERT INTO ROBOT (NAME, TYPE)</span>\n<span class=\"ss\">    VALUES (&quot;</span><span class=\"n\">JIM</span><span class=\"ss\">&quot;, &quot;</span><span class=\"n\">DEFENSIVE</span><span class=\"ss\">&quot;), (&quot;</span><span class=\"n\">JACK</span><span class=\"ss\">&quot;, &quot;</span><span class=\"n\">OFFENSIVE</span><span class=\"ss\">&quot;)</span>\n<span class=\"ss\">&quot;&quot;&quot;</span><span class=\"p\">)</span>\n\n<span class=\"o\">#</span> <span class=\"n\">Dot&#xE1;&#x17E;eme</span> <span class=\"n\">se</span> <span class=\"n\">na</span> <span class=\"n\">v&#x161;echny</span> <span class=\"n\">roboty</span><span class=\"p\">,</span> <span class=\"n\">v&#xFD;sledky</span> <span class=\"n\">vyp&#xED;&#x161;eme</span>\n<span class=\"n\">robots</span> <span class=\"o\">=</span> <span class=\"k\">cursor</span><span class=\"p\">.</span><span class=\"k\">execute</span><span class=\"p\">(</span><span class=\"ss\">&quot;SELECT * FROM ROBOT&quot;</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">robot</span> <span class=\"k\">in</span> <span class=\"n\">robots</span><span class=\"p\">:</span>\n    <span class=\"n\">print</span><span class=\"p\">(</span><span class=\"n\">robot</span><span class=\"p\">)</span>\n\n<span class=\"o\">#</span> <span class=\"n\">Ulo&#x17E;&#xED;me</span> <span class=\"n\">zm&#x11B;ny</span> <span class=\"n\">a</span> <span class=\"n\">uzav&#x159;eme</span> <span class=\"n\">spojen&#xED;</span>\n<span class=\"k\">connection</span><span class=\"p\">.</span><span class=\"k\">commit</span><span class=\"p\">()</span>\n<span class=\"k\">connection</span><span class=\"p\">.</span><span class=\"k\">close</span><span class=\"p\">()</span>\n</pre></div><div class=\"highlight\"><pre><span></span><span class=\"o\">#</span> <span class=\"n\">Slo&#x17E;itej&#x161;&#xED;</span> <span class=\"n\">p&#x159;&#xED;klad</span><span class=\"p\">,</span> <span class=\"n\">kter&#xFD;</span> <span class=\"n\">pracuje</span> <span class=\"n\">s</span> <span class=\"n\">prim&#xE1;rn&#xED;mi</span> <span class=\"n\">a</span> <span class=\"n\">ciz&#xED;mi</span> <span class=\"n\">kl&#xED;&#x10D;i</span>\n<span class=\"o\">#</span> <span class=\"n\">a</span> <span class=\"n\">se</span> <span class=\"n\">spojov&#xE1;n&#xED;m</span> <span class=\"n\">tabulek</span>\n\n<span class=\"n\">import</span> <span class=\"n\">sqlite3</span>\n\n<span class=\"o\">#</span> <span class=\"n\">P&#x159;ipoj&#xED;me</span> <span class=\"n\">se</span> <span class=\"n\">k</span> <span class=\"n\">datab&#xE1;zi</span> <span class=\"p\">(</span><span class=\"n\">v</span> <span class=\"n\">souboru</span><span class=\"p\">)</span>\n<span class=\"k\">connection</span> <span class=\"o\">=</span> <span class=\"n\">sqlite3</span><span class=\"p\">.</span><span class=\"k\">connect</span><span class=\"p\">(</span><span class=\"s1\">&apos;pyladies_example_2.db&apos;</span><span class=\"p\">)</span>\n\n<span class=\"o\">#</span> <span class=\"n\">Z&#xED;sk&#xE1;me</span> <span class=\"n\">instanci</span> <span class=\"n\">t&#x159;&#xED;dy</span> <span class=\"o\">`</span><span class=\"k\">Cursor</span><span class=\"o\">`</span><span class=\"p\">,</span> <span class=\"n\">pomoc&#xED;</span> <span class=\"n\">kter&#xE9;</span> <span class=\"n\">bude</span> <span class=\"k\">do</span> <span class=\"n\">datab&#xE1;ze</span> <span class=\"n\">pos&#xED;lat</span> <span class=\"n\">p&#x159;&#xED;kazy</span>\n<span class=\"k\">cursor</span> <span class=\"o\">=</span> <span class=\"k\">connection</span><span class=\"p\">.</span><span class=\"k\">cursor</span><span class=\"p\">()</span>\n\n<span class=\"o\">#</span> <span class=\"n\">Pokud</span> <span class=\"n\">tabulky</span> <span class=\"n\">u&#x17E;</span> <span class=\"n\">existuj&#xED;</span><span class=\"p\">,</span> <span class=\"n\">tak</span> <span class=\"n\">ji</span> <span class=\"n\">odstran&#xED;me</span><span class=\"p\">,</span>\n<span class=\"o\">#</span> <span class=\"n\">abychom</span> <span class=\"n\">mohli</span> <span class=\"n\">skript</span> <span class=\"n\">spou&#x161;t&#x11B;t</span> <span class=\"n\">opakovan&#x11B;</span>\n<span class=\"k\">cursor</span><span class=\"p\">.</span><span class=\"k\">execute</span><span class=\"p\">(</span><span class=\"ss\">&quot;&quot;&quot;DROP TABLE IF EXISTS ROBOT&quot;&quot;&quot;</span><span class=\"p\">)</span>\n<span class=\"k\">cursor</span><span class=\"p\">.</span><span class=\"k\">execute</span><span class=\"p\">(</span><span class=\"ss\">&quot;&quot;&quot;DROP TABLE IF EXISTS BATTLE&quot;&quot;&quot;</span><span class=\"p\">)</span>\n\n<span class=\"o\">#</span> <span class=\"n\">Vytvo&#x159;&#xED;me</span> <span class=\"n\">tabulku</span> <span class=\"n\">s</span> <span class=\"n\">roboty</span> <span class=\"n\">a</span> <span class=\"n\">tabulky</span> <span class=\"n\">s</span> <span class=\"n\">v&#xFD;sledky</span> <span class=\"n\">bitev</span>\n<span class=\"k\">cursor</span><span class=\"p\">.</span><span class=\"k\">execute</span><span class=\"p\">(</span><span class=\"ss\">&quot;&quot;&quot;</span>\n<span class=\"ss\">-- u jednotliv&#xFD;ch robor&#x16F; si ukl&#xE1;d&#xE1;me ID, jm&#xE9;no a typ</span>\n<span class=\"ss\">CREATE TABLE ROBOT (</span>\n<span class=\"ss\">    ROBOT_ID INT PRIMARY KEY,</span>\n<span class=\"ss\">    NAME TEXT,</span>\n<span class=\"ss\">    TYPE TEXT)</span>\n<span class=\"ss\">&quot;&quot;&quot;</span><span class=\"p\">)</span>\n\n<span class=\"k\">cursor</span><span class=\"p\">.</span><span class=\"k\">execute</span><span class=\"p\">(</span><span class=\"ss\">&quot;&quot;&quot;</span>\n<span class=\"ss\">-- bitva se skl&#xE1;d&#xE1; z ID bitvy, ID v&#xED;t&#x11B;ze a pora&#x17E;en&#xE9;ho (odpov&#xED;daj&#xED; ID v tabulce ROBOT)</span>\n<span class=\"ss\">-- a z bod&#x16F; pro v&#xED;t&#x11B;ze a pora&#x17E;en&#xE9;ho</span>\n<span class=\"ss\">CREATE TABLE BATTLE (</span>\n<span class=\"ss\">    BATTLE_ID INT PRIMARY KEY,</span>\n<span class=\"ss\">    WINNER_ID INT,</span>\n<span class=\"ss\">    LOSER_ID INT,</span>\n<span class=\"ss\">    WINNER_POINTS INT,</span>\n<span class=\"ss\">    LOSER_POINTS INT,</span>\n<span class=\"ss\">    FOREIGN KEY(WINNER_ID) REFERENCES ROBOT(ROBOT_ID),</span>\n<span class=\"ss\">    FOREIGN KEY(LOSER_ID) REFERENCES ROBOT(ROBOT_ID)</span>\n<span class=\"ss\">    )</span>\n<span class=\"ss\">&quot;&quot;&quot;</span><span class=\"p\">)</span>\n\n<span class=\"o\">#</span> <span class=\"n\">Vlo&#x17E;&#xED;me</span> <span class=\"k\">do</span> <span class=\"n\">tabulkek</span> <span class=\"k\">data</span>\n<span class=\"k\">cursor</span><span class=\"p\">.</span><span class=\"k\">execute</span><span class=\"p\">(</span><span class=\"ss\">&quot;&quot;&quot;</span>\n<span class=\"ss\">    INSERT INTO ROBOT (ROBOT_ID, NAME, TYPE) VALUES</span>\n<span class=\"ss\">    (1, &quot;</span><span class=\"n\">JIM</span><span class=\"ss\">&quot;, &quot;</span><span class=\"n\">DEFENSIVE</span><span class=\"ss\">&quot;), (2, &quot;</span><span class=\"n\">JACK</span><span class=\"ss\">&quot;, &quot;</span><span class=\"n\">OFFENSIVE</span><span class=\"ss\">&quot;), (3, &quot;</span><span class=\"n\">JIMMY</span><span class=\"ss\">&quot;, &quot;</span><span class=\"n\">OFFESIVE</span><span class=\"ss\">&quot;)</span>\n<span class=\"ss\">&quot;&quot;&quot;</span><span class=\"p\">)</span>\n\n<span class=\"k\">cursor</span><span class=\"p\">.</span><span class=\"k\">execute</span><span class=\"p\">(</span><span class=\"ss\">&quot;&quot;&quot;</span>\n<span class=\"ss\">    INSERT INTO BATTLE (BATTLE_ID, WINNER_ID, LOSER_ID, WINNER_POINTS, LOSER_POINTS) VALUES</span>\n<span class=\"ss\">    (1, 1, 2, 10, 8), -- robot 1 porazil robota 2 se sk&#xF3;re 10:8 (v bitv&#x11B; 1)</span>\n<span class=\"ss\">    (2, 2, 1, 6, 9),</span>\n<span class=\"ss\">    (3, 2, 3, 10, 9),</span>\n<span class=\"ss\">    (4, 1, 3, 5, 4),</span>\n<span class=\"ss\">    (5, 3, 2, 2, 0),</span>\n<span class=\"ss\">    (6, 1, 2, 9, 6)</span>\n<span class=\"ss\">&quot;&quot;&quot;</span><span class=\"p\">)</span>\n\n<span class=\"o\">#</span> <span class=\"n\">Dot&#xE1;&#x17E;eme</span> <span class=\"n\">se</span> <span class=\"n\">na</span> <span class=\"n\">v&#xFD;sledky</span> <span class=\"n\">bitev</span><span class=\"p\">,</span> <span class=\"n\">kter&#xE9;</span> <span class=\"n\">vyhr&#xE1;l</span> <span class=\"n\">robot</span> <span class=\"n\">se</span> <span class=\"n\">jm&#xE9;nem</span> <span class=\"ss\">&quot;JIM&quot;</span>\n<span class=\"n\">scores</span> <span class=\"o\">=</span> <span class=\"k\">cursor</span><span class=\"p\">.</span><span class=\"k\">execute</span><span class=\"p\">(</span><span class=\"ss\">&quot;&quot;&quot;</span>\n<span class=\"ss\">    SELECT BATTLE.WINNER_POINTS, BATTLE.LOSER_POINTS</span>\n<span class=\"ss\">    FROM BATTLE</span>\n<span class=\"ss\">    JOIN ROBOT ON ROBOT.ROBOT_ID = BATTLE.WINNER_ID</span>\n<span class=\"ss\">    WHERE ROBOT.NAME = &quot;</span><span class=\"n\">JIM</span><span class=\"ss\">&quot;</span>\n<span class=\"ss\">&quot;&quot;&quot;</span><span class=\"p\">)</span>\n\n<span class=\"k\">for</span> <span class=\"n\">score</span> <span class=\"k\">in</span> <span class=\"n\">scores</span><span class=\"p\">:</span>\n    <span class=\"n\">print</span><span class=\"p\">(</span><span class=\"n\">score</span><span class=\"p\">)</span>\n\n<span class=\"o\">#</span> <span class=\"n\">Ulo&#x17E;&#xED;me</span> <span class=\"n\">zm&#x11B;ny</span> <span class=\"n\">a</span> <span class=\"n\">uzav&#x159;eme</span> <span class=\"n\">spojen&#xED;</span>\n<span class=\"k\">connection</span><span class=\"p\">.</span><span class=\"k\">commit</span><span class=\"p\">()</span>\n<span class=\"k\">connection</span><span class=\"p\">.</span><span class=\"k\">close</span><span class=\"p\">()</span>\n</pre></div><h2>ORM</h2>\n<p>V Pythonu jsme se nau&#x10D;ili data a logiku sdru&#x17E;ovat do <strong>t&#x159;&#xED;d</strong>. V datab&#xE1;z&#xED;ch\nse data sdru&#x17E;uj&#xED; do <strong>tabulek</strong>. O propojen&#xED; t&#x11B;chto koncept&#x16F; se star&#xE1; ORM - Objektov&#x11B;\nRela&#x10D;n&#xED; Mapov&#xE1;n&#xED;. Pomoc&#xED; ORM Frameworku (v Pythonu nap&#x159;.\n<a href=\"https://en.wikipedia.org/wiki/SQLAlchemy\">SQLAlchemy</a>) vytv&#xE1;&#x159;&#xED;me Python t&#x159;&#xED;dy,\npro kter&#xE9; existuj&#xED; odpov&#xED;daj&#xED;c&#xED; tabulky v datab&#xE1;zi.</p>\n<p>Nap&#x159;&#xED;klad Python t&#x159;&#xED;da <code>Kocka</code> bude m&#xED;t odpov&#xED;daj&#xED;c&#xED; tabulku <code>KOCKA</code>.\nAtributy t&#x159;&#xED;dy (<code>Vek</code>, <code>Barva</code>) budou v datab&#xE1;zi existovat jako sloupce.\nJednotliv&#xE9; &#x159;&#xE1;dky tabulky bude mo&#x17E;n&#xE9; na&#x10D;&#xED;st do aplikace jako instance t&#x159;&#xED;dy <code>Kocka</code>.\nJednotliv&#xE9; ko&#x10D;ky samoz&#x159;ejm&#x11B; bude mo&#x17E;n&#xE9; upravovat, mazat, nebo vytv&#xE1;&#x159;et nov&#xE9;.</p>\n<p>Uk&#xE1;zku ORM najdete na <a href=\"https://en.wikipedia.org/wiki/SQLAlchemy#Schema_definition\">Wikipedii</a></p>\n\n\n        "
    }
  }
}