diff --git a/lessons/pydata/databases/index.ipynb b/lessons/pydata/databases/index.ipynb index 89805fa8aa..aa53e07734 100644 --- a/lessons/pydata/databases/index.ipynb +++ b/lessons/pydata/databases/index.ipynb @@ -53,16 +53,16 @@ "\n", "Od databáze (resp. databázového systému) očekáváme několik vlastností:\n", "\n", - "- Že bude uchovávat data :) Ne, vážně - data musí zůstat beze ztráty uložena i v případě výpadku napájení, když dojde místo na disku...\n", + "- Že bude uchovávat data :) Ne, vážně - data musí zůstat beze ztráty uložena i v případě výpadku napájení, když dojde místo na disku... Že existují nástroje pro zálohování a obnovu databáze.\n", "- Práce s daty \"z různých úhlů\". Např. v e-shopu chceme jednou vypsat zboží podle kategorie, jindy podle stavu skladových zásob, jindy na základě full-textového vyhledávání..\n", - "- Podpora uživatelů, rolí, oprávnění a kontroly přístupu k datům, security.\n", - "- Rychlost, výkon, propustnost, latence\n", + "- Podpora uživatelů, rolí, oprávnění a kontroly přístupu k datům.\n", + "- Rychlost, výkon, propustnost, nízká latence\n", "- Škálovatelnost - jak do velikosti (gigabajty, terabajty, petabajty), tak do počtu prováděných operací za sekundu\n", "- ACID\n", - " - Atomicity:\n", - " - Consistency:\n", - " - Isolation:\n", - " - Durability:\n", + " - **Atomicity**: celá transakce (série několika databázových operací) se provede celá, nebo vůbec\n", + " - **Consistency**: nesmí být narušena integrita dat, tj. podmínek definových v databázovém schématu (např. unikátní hodnoty, reference řádků mezi tabulkami...)\n", + " - **Isolation**: vícero současně probíhajících transakcí se nesmí navzájem ovlivnit\n", + " - **Durability**: jakmile je transakce dokončena, je zaznamenána trvalým způsobem, nesmaže ji např. výpadek napájení\n", " \n", "Když se nad tím zamyslíte, jedná se o protichůdné požadavky. Tvůrci databázových systémů tak musí zvolit nějaký kompomis. Někdy lze databáze nakonfigurovat, zda má např. preferovat izolaci, nebo propustnost (viz [PostgreSQL Transaction Isolation](https://www.postgresql.org/docs/9.5/transaction-iso.html)). Žádná databáze není \"nejlepší\" a vhodná na všechno. Zrovna co se týče rozdílu mezi \"transakční\" a \"analytickou\" databází, tak často pro tyto oblasti jsou vhodné odlišné systémy a přístupy.\n", " " @@ -115,11 +115,11 @@ "\n", "Co když chceme vyjádřit možnost, že jeden film může mít více než jednoho režiséra?\n", "\n", - "| movie_id | title | year | director_id |\n", - "|----------|:----------------------|:-----|:------------|\n", - "| 1 | Pelíšky | 1999 | 1 |\n", - "| 2 | Forrest Gump | 1994 | 2 |\n", - "| 3 | Návrat do budoucnosti | 1985 | 2 |\n", + "| movie_id | title | year |\n", + "|----------|:----------------------|:-----|\n", + "| 1 | Pelíšky | 1999 |\n", + "| 2 | Forrest Gump | 1994 |\n", + "| 3 | Návrat do budoucnosti | 1985 |\n", "\n", "| director_id | name | birthdate |\n", "|-------------|:----------------|------------|\n", @@ -394,6 +394,14 @@ "Na prozkoumání struktury a obsahu databáze můžete použít nějaký specializovaný program - [DB Browser](https://sqlitebrowser.org/), [DBeaver](https://dbeaver.io/), [MySQL Workbench](https://www.mysql.com/products/workbench/), ... je jich hodně, typicky se specializují na konkrétní druh databáze, některé programy jsou zdarma a některé placené. Existují i webové aplikace, nejznámější asi český [Adminer](https://www.adminer.org/). Zde jsem vám chtěl ukázat, že toho samého se dá dosáhnout i takto z Pythonu." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Poznámka: struktura této databáze je trochu jiná, než byl motivační příklad na začátku.\n", + "Nemáme tu `directors`, máme tu `actors`." + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -411,7 +419,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 10, @@ -491,9 +499,9 @@ "source": [ "Jde o SQLAlchemy objekt RowProxy, který umí pár zajímavých věcí:\n", "\n", - "- vrátit hodnotu daného sloupce podle pořadí \n", - "- vrátit hodnotu daného sloupce podle názvu\n", - "- vrátit dict s hodnotami" + "- vrátit hodnotu daného sloupce podle pořadí – např. `row[2]`\n", + "- vrátit hodnotu daného sloupce podle názvu – např. `row[\"name\"]`\n", + "- vrátit dict s hodnotami – např. `dict(row)`" ] }, { @@ -519,6 +527,13 @@ " print(row[0], row[1])" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Poznámka: sloupce vyjmenované za `SELECT` mohou být v jakémkoli pořadí. Stejně tak vytahávat si je z toho `RowProxy` objektu také můžeme libovolně v jakémkoli pořadí. " + ] + }, { "cell_type": "code", "execution_count": 14, @@ -528,18 +543,25 @@ "name": "stdout", "output_type": "stream", "text": [ - "1 Tim Robbins\n", - "2 Morgan Freeman\n", - "3 Bob Gunton\n", - "4 William Sadler\n", - "5 Clancy Brown\n" + "https://www.csfd.cz/tvurce/103-tim-robbins/ Tim Robbins\n", + "https://www.csfd.cz/tvurce/92-morgan-freeman/ Morgan Freeman\n", + "https://www.csfd.cz/tvurce/202-bob-gunton/ Bob Gunton\n", + "https://www.csfd.cz/tvurce/203-william-sadler/ William Sadler\n", + "https://www.csfd.cz/tvurce/204-clancy-brown/ Clancy Brown\n" ] } ], "source": [ - "result = engine.execute('SELECT id, name, csfd_url FROM actors LIMIT 5')\n", + "result = engine.execute('SELECT name, id, csfd_url FROM actors LIMIT 5')\n", "for row in result:\n", - " print(row['id'], row['name'])" + " print(row[2], row[0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Pomocí `SELECT *` si vytáhneme všechny dostupné sloupce:" ] }, { @@ -551,31 +573,55 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'id': 1, 'name': 'Tim Robbins', 'csfd_url': 'https://www.csfd.cz/tvurce/103-tim-robbins/'}\n", - "{'id': 2, 'name': 'Morgan Freeman', 'csfd_url': 'https://www.csfd.cz/tvurce/92-morgan-freeman/'}\n", - "{'id': 3, 'name': 'Bob Gunton', 'csfd_url': 'https://www.csfd.cz/tvurce/202-bob-gunton/'}\n", - "{'id': 4, 'name': 'William Sadler', 'csfd_url': 'https://www.csfd.cz/tvurce/203-william-sadler/'}\n", - "{'id': 5, 'name': 'Clancy Brown', 'csfd_url': 'https://www.csfd.cz/tvurce/204-clancy-brown/'}\n" + "(1, 'https://www.csfd.cz/tvurce/103-tim-robbins/', 'Tim Robbins', '1958-10-16')\n", + "(2, 'https://www.csfd.cz/tvurce/92-morgan-freeman/', 'Morgan Freeman', '1937-06-01')\n", + "(3, 'https://www.csfd.cz/tvurce/202-bob-gunton/', 'Bob Gunton', '1945-11-15')\n", + "(4, 'https://www.csfd.cz/tvurce/203-william-sadler/', 'William Sadler', '1950-04-13')\n", + "(5, 'https://www.csfd.cz/tvurce/204-clancy-brown/', 'Clancy Brown', '1959-01-05')\n" ] } ], "source": [ - "result = engine.execute('SELECT id, name, csfd_url FROM actors LIMIT 5')\n", + "result = engine.execute('SELECT * FROM actors LIMIT 5')\n", "for row in result:\n", - " print(dict(row))" + " print(row)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Pokud chceme získat hodnoty ze všech sloupečků, použijeme hvězdičku." + "Asi bude lepší místo `row[2]` používat např. `row[\"name\"]`,\n", + "nebo si to převést celé do slovníku přes `dict(row)`:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 Tim Robbins 1958-10-16\n", + "2 Morgan Freeman 1937-06-01\n", + "3 Bob Gunton 1945-11-15\n", + "4 William Sadler 1950-04-13\n", + "5 Clancy Brown 1959-01-05\n" + ] + } + ], + "source": [ + "result = engine.execute('SELECT * FROM actors LIMIT 5')\n", + "for row in result:\n", + " print(row['id'], row['name'], row['birth_date'])" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -599,12 +645,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Z dat lze vytvořit i Pandas DataFrame:" + "Z dat lze vytvořit i **Pandas DataFrame**:" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -629,55 +675,131 @@ " \n", " \n", " id\n", + " csfd_url\n", " name\n", + " birth_date\n", " \n", " \n", " \n", " \n", " 0\n", " 1\n", + " https://www.csfd.cz/tvurce/103-tim-robbins/\n", " Tim Robbins\n", + " 1958-10-16\n", " \n", " \n", " 1\n", " 2\n", + " https://www.csfd.cz/tvurce/92-morgan-freeman/\n", " Morgan Freeman\n", + " 1937-06-01\n", " \n", " \n", " 2\n", " 3\n", + " https://www.csfd.cz/tvurce/202-bob-gunton/\n", " Bob Gunton\n", + " 1945-11-15\n", " \n", " \n", " 3\n", " 4\n", + " https://www.csfd.cz/tvurce/203-william-sadler/\n", " William Sadler\n", + " 1950-04-13\n", " \n", " \n", " 4\n", " 5\n", + " https://www.csfd.cz/tvurce/204-clancy-brown/\n", " Clancy Brown\n", + " 1959-01-05\n", + " \n", + " \n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " \n", + " \n", + " 7522\n", + " 7523\n", + " https://www.csfd.cz/tvurce/147104-jon-kenny/\n", + " Jon Kenny\n", + " None\n", + " \n", + " \n", + " 7523\n", + " 7524\n", + " https://www.csfd.cz/tvurce/147105-lisa-hannigan/\n", + " Lisa Hannigan\n", + " 1981-02-12\n", + " \n", + " \n", + " 7524\n", + " 7525\n", + " https://www.csfd.cz/tvurce/162204-lucy-o-connell/\n", + " Lucy O'Connell\n", + " None\n", + " \n", + " \n", + " 7525\n", + " 7526\n", + " https://www.csfd.cz/tvurce/309228-paul-young/\n", + " Paul Young\n", + " None\n", + " \n", + " \n", + " 7526\n", + " 7527\n", + " https://www.csfd.cz/tvurce/458624-grethe-mogen...\n", + " Grethe Mogensen\n", + " 1937-05-25\n", " \n", " \n", "\n", + "

7527 rows × 4 columns

\n", "" ], "text/plain": [ - " id name\n", - "0 1 Tim Robbins\n", - "1 2 Morgan Freeman\n", - "2 3 Bob Gunton\n", - "3 4 William Sadler\n", - "4 5 Clancy Brown" + " id csfd_url \\\n", + "0 1 https://www.csfd.cz/tvurce/103-tim-robbins/ \n", + "1 2 https://www.csfd.cz/tvurce/92-morgan-freeman/ \n", + "2 3 https://www.csfd.cz/tvurce/202-bob-gunton/ \n", + "3 4 https://www.csfd.cz/tvurce/203-william-sadler/ \n", + "4 5 https://www.csfd.cz/tvurce/204-clancy-brown/ \n", + "... ... ... \n", + "7522 7523 https://www.csfd.cz/tvurce/147104-jon-kenny/ \n", + "7523 7524 https://www.csfd.cz/tvurce/147105-lisa-hannigan/ \n", + "7524 7525 https://www.csfd.cz/tvurce/162204-lucy-o-connell/ \n", + "7525 7526 https://www.csfd.cz/tvurce/309228-paul-young/ \n", + "7526 7527 https://www.csfd.cz/tvurce/458624-grethe-mogen... \n", + "\n", + " name birth_date \n", + "0 Tim Robbins 1958-10-16 \n", + "1 Morgan Freeman 1937-06-01 \n", + "2 Bob Gunton 1945-11-15 \n", + "3 William Sadler 1950-04-13 \n", + "4 Clancy Brown 1959-01-05 \n", + "... ... ... \n", + "7522 Jon Kenny None \n", + "7523 Lisa Hannigan 1981-02-12 \n", + "7524 Lucy O'Connell None \n", + "7525 Paul Young None \n", + "7526 Grethe Mogensen 1937-05-25 \n", + "\n", + "[7527 rows x 4 columns]" ] }, - "execution_count": 17, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "pd.read_sql_query('SELECT id, name FROM actors LIMIT 5', engine)" + "pd.read_sql_query('SELECT * FROM actors', engine)" ] }, { @@ -689,7 +811,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "metadata": {}, "outputs": [ { @@ -832,7 +954,7 @@ "[7527 rows x 4 columns]" ] }, - "execution_count": 18, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -854,7 +976,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -863,7 +985,7 @@ "['actors', 'movie_to_actor', 'movies']" ] }, - "execution_count": 19, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -874,7 +996,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -885,7 +1007,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -971,7 +1093,7 @@ "4 1959-01-05 " ] }, - "execution_count": 21, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -982,7 +1104,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 23, "metadata": {}, "outputs": [ { @@ -1074,7 +1196,7 @@ "4 https://www.csfd.cz/film/2671-sedm/ 1995 92.4 " ] }, - "execution_count": 22, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -1085,7 +1207,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 24, "metadata": {}, "outputs": [ { @@ -1158,7 +1280,7 @@ "4 5 1 5" ] }, - "execution_count": 23, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -1176,7 +1298,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 25, "metadata": {}, "outputs": [ { @@ -1187,18 +1309,21 @@ " (6290, 'https://www.csfd.cz/tvurce/35296-morgan-lily/', 'Morgan Lily', '2000-04-11')]" ] }, - "execution_count": 24, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "list(engine.execute('SELECT * FROM actors WHERE birth_date > \"2000-01-01\" AND birth_date < \"2001-01-01\"'))" + "list(engine.execute('''\n", + " SELECT * FROM actors \n", + " WHERE birth_date > \"2000-01-01\" AND birth_date < \"2001-01-01\"\n", + "'''))" ] }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -1266,7 +1391,7 @@ "6289 2000-04-11 " ] }, - "execution_count": 25, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -1284,7 +1409,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 27, "metadata": {}, "outputs": [ { @@ -1297,19 +1422,24 @@ " (1865, 'https://www.csfd.cz/tvurce/354371-pierce-pope/', 'Pierce Pope', '2008-06-02')]" ] }, - "execution_count": 26, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "list(engine.execute('SELECT * FROM actors WHERE birth_date > \"2005-01-01\" ORDER BY birth_date ASC'))" + "list(engine.execute('''\n", + " SELECT * FROM actors \n", + " WHERE birth_date > \"2005-01-01\" \n", + " ORDER BY birth_date ASC'''))" ] }, { "cell_type": "code", - "execution_count": 27, - "metadata": {}, + "execution_count": 28, + "metadata": { + "scrolled": true + }, "outputs": [ { "data": { @@ -1394,7 +1524,7 @@ "1864 Pierce Pope 2008-06-02 " ] }, - "execution_count": 27, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -1407,78 +1537,814 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## SELECT ... GROUP BY" + "Při řazení podle více sloupců pozor na pořadí :)" ] }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 29, "metadata": {}, "outputs": [ { "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
titleyearrating
0Pán prstenů: Společenstvo Prstenu200190.4
1Pán prstenů: Návrat krále200390.3
2Temný rytíř200890.2
3Gran Torino200890.3
4Nedotknutelní201191.3
5Le Mans '66201990.5
6Gentlemani201990.4
\n", + "
" + ], "text/plain": [ - "[(1957, 6),\n", - " (1968, 6),\n", - " (1973, 6),\n", - " (1980, 6),\n", - " (1984, 6),\n", - " (1986, 7),\n", - " (1990, 7),\n", - " (1991, 6),\n", - " (1993, 11),\n", - " (1995, 7),\n", - " (1997, 8),\n", - " (1998, 6),\n", - " (1999, 9),\n", - " (2000, 6),\n", - " (2001, 8),\n", - " (2002, 6),\n", - " (2003, 6),\n", - " (2004, 9),\n", - " (2008, 6)]" + " title year rating\n", + "0 Pán prstenů: Společenstvo Prstenu 2001 90.4\n", + "1 Pán prstenů: Návrat krále 2003 90.3\n", + "2 Temný rytíř 2008 90.2\n", + "3 Gran Torino 2008 90.3\n", + "4 Nedotknutelní 2011 91.3\n", + "5 Le Mans '66 2019 90.5\n", + "6 Gentlemani 2019 90.4" ] }, - "execution_count": 28, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "list(engine.execute('SELECT year, COUNT(*) FROM movies GROUP BY year HAVING COUNT(*) > 5'))" + "pd.read_sql_query('''\n", + " SELECT title, year, rating FROM movies \n", + " WHERE rating > 90 AND year >= 2000\n", + " ORDER BY year ASC, title DESC\n", + "''', engine)" ] }, { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Úkol: který herec účinkoval v největším počtu filmů\n", - "\n", - "Najděte v tabulce `movie_to_actor` id herce, u kterého je v té tabulce nejvíce id filmů.\n", - "\n", - "Postup:\n", - "\n", - "1. Pomocí GROUP BY si vypište vždy actor_id a k tomu počet řádků s tímto actor_id\n", - "2. Pomocí ORDER BY a LIMIT zjistěte actor_id, u kterého je tento počet nejvyšší\n", - "3. Bonus: zjistěte jméno tohoto herce" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## JOIN\n", - "\n", - "TODO: tady bude ukázka JOIN v SQL vs. merge v DataFrame\n", - "\n", - "
" - ] - }, - { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 30, "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idtitlecsfd_urlyearrating
1617Pán prstenů: Společenstvo Prstenuhttps://www.csfd.cz/film/4711-pan-prstenu-spol...200190.4
1718Pán prstenů: Návrat králehttps://www.csfd.cz/film/4712-pan-prstenu-navr...200390.3
1920Temný rytířhttps://www.csfd.cz/film/223734-temny-rytir/200890.2
1819Gran Torinohttps://www.csfd.cz/film/240479-gran-torino/200890.3
78Nedotknutelníhttps://www.csfd.cz/film/306731-nedotknutelni/201191.3
2122Gentlemanihttps://www.csfd.cz/film/675173-gentlemani/201990.4
1516Le Mans '66https://www.csfd.cz/film/332773-le-mans-66/201990.5
\n", + "
" + ], + "text/plain": [ + " id title \\\n", + "16 17 Pán prstenů: Společenstvo Prstenu \n", + "17 18 Pán prstenů: Návrat krále \n", + "19 20 Temný rytíř \n", + "18 19 Gran Torino \n", + "7 8 Nedotknutelní \n", + "21 22 Gentlemani \n", + "15 16 Le Mans '66 \n", + "\n", + " csfd_url year rating \n", + "16 https://www.csfd.cz/film/4711-pan-prstenu-spol... 2001 90.4 \n", + "17 https://www.csfd.cz/film/4712-pan-prstenu-navr... 2003 90.3 \n", + "19 https://www.csfd.cz/film/223734-temny-rytir/ 2008 90.2 \n", + "18 https://www.csfd.cz/film/240479-gran-torino/ 2008 90.3 \n", + "7 https://www.csfd.cz/film/306731-nedotknutelni/ 2011 91.3 \n", + "21 https://www.csfd.cz/film/675173-gentlemani/ 2019 90.4 \n", + "15 https://www.csfd.cz/film/332773-le-mans-66/ 2019 90.5 " + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "movies[(movies['rating'] > 90) & (movies['year'] >= 2000)] \\\n", + " .sort_values('rating').sort_values('year')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## SELECT ... GROUP BY\n", + "\n", + "GROUP BY umožňuje \"shluknout\" řádky do *skupin*, a nad těmito skupinami pak provádět agregační funkce (MIN, MAX, AVG, COUNT apod.).\n", + "\n", + "Tyto skupiny pak lze dále filtrovat pomocí HAVING (podobně jako WHERE filtruje *řádky*, a to *předtím*, než se z nich vytvářejí ty *skupiny*)." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[(1993, 11),\n", + " (2004, 9),\n", + " (1999, 9),\n", + " (2001, 8),\n", + " (1997, 8),\n", + " (1995, 7),\n", + " (1990, 7),\n", + " (1986, 7),\n", + " (2008, 6),\n", + " (2003, 6),\n", + " (2002, 6),\n", + " (2000, 6),\n", + " (1998, 6),\n", + " (1991, 6),\n", + " (1984, 6),\n", + " (1980, 6),\n", + " (1973, 6),\n", + " (1968, 6),\n", + " (1957, 6)]" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(engine.execute('''\n", + " SELECT year, COUNT(*) FROM movies GROUP BY year \n", + " HAVING COUNT(*) > 5 ORDER BY COUNT(*) DESC '''))" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
yearCOUNT(id)MIN(rating)AVG(rating)MAX(rating)
02004984.585.77777887.9
12001884.786.85000090.4
21999984.687.92222292.8
31997884.686.58750089.1
419931184.686.02727392.3
\n", + "
" + ], + "text/plain": [ + " year COUNT(id) MIN(rating) AVG(rating) MAX(rating)\n", + "0 2004 9 84.5 85.777778 87.9\n", + "1 2001 8 84.7 86.850000 90.4\n", + "2 1999 9 84.6 87.922222 92.8\n", + "3 1997 8 84.6 86.587500 89.1\n", + "4 1993 11 84.6 86.027273 92.3" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.read_sql_query('''\n", + " SELECT year, COUNT(id), MIN(rating), AVG(rating), MAX(rating) \n", + " FROM movies \n", + " WHERE rating > 10\n", + " GROUP BY year\n", + " HAVING COUNT(id) > 7\n", + " ORDER BY year DESC\n", + " ''', engine)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To GROUP BY je potřeba, protože bez toho se bude *celá* tabulka považovat za jedinou *skupinu* a použití agregačních funkcí způsobí to, že se vám vrátí jen jeden řádek výsledků:" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
COUNT(*)MIN(birth_date)MAX(birth_date)
075271857-11-112008-06-02
\n", + "
" + ], + "text/plain": [ + " COUNT(*) MIN(birth_date) MAX(birth_date)\n", + "0 7527 1857-11-11 2008-06-02" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.read_sql_query('''\n", + " SELECT COUNT(*), MIN(birth_date), MAX(birth_date)\n", + " FROM actors \n", + " ''', engine)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Jaký je rozdíl mezi `COUNT(*)`, `COUNT(id)` a `COUNT(něco)`?\n", + "\n", + "`COUNT(*)` vrací počet řádků. `COUNT(sloupec)` vrací počet řádků, ve kterých je v daném sloupci nějaká hodnota (tj. není tam NULL). Pokud tím sloupcem je `id`, který je téměř vždy NON-NULL, tak je `COUNT(id)` a `COUNT(*)` vlastně to samé :)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
COUNT(*)COUNT(id)COUNT(birth_date)
0752775275753
\n", + "
" + ], + "text/plain": [ + " COUNT(*) COUNT(id) COUNT(birth_date)\n", + "0 7527 7527 5753" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.read_sql_query('''\n", + " SELECT COUNT(*), COUNT(id), COUNT(birth_date) \n", + " FROM actors \n", + " ''', engine)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Jak je vidět, u některých herců není vyplněno `birth_date`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Struktura SQL dotazu\n", + "\n", + "Ještě rekapitulace, jak se probíhá provádění SQL dotazu :)\n", + "\n", + "1. databáze vezme tabulky vyjmenované ve FROM\n", + "2. databáze čte řádky (jeden po druhém)\n", + "3. ty řádky se filtrují podle uvedených WHERE výrazů\n", + "4. přefiltrované řádky se seskupí podle GROUP BY výrazů do skupin\n", + "5. ty skupiny se filtrují pode uvedených HAVING výrazů\n", + "6. výsledek se seřadí podle ORDER BY\n", + "7. výsledek se ořízne podle LIMIT\n", + "\n", + "Probrali jsme jen to nejdůležitější. Pro představu, jaké jsou možnosti zápisu SELECT dotazu\n", + "(převzato z [dokumentace SQLite](https://www.sqlite.org/lang_select.html)):\n", + "\n", + "


" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Úkol: který herec účinkoval v největším počtu filmů\n", + "\n", + "Najděte v tabulce `movie_to_actor` id herce, u kterého je v té tabulce nejvíce id filmů.\n", + "\n", + "Postup:\n", + "\n", + "1. Pomocí GROUP BY si vypište vždy actor_id a k tomu počet řádků s tímto actor_id\n", + "2. Pomocí ORDER BY a LIMIT zjistěte actor_id, u kterého je tento počet nejvyšší\n", + "3. Bonus: zjistěte jméno tohoto herce" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## JOIN\n", + "\n", + "JOIN je v SQL to samé, co je merge v DataFrame (viz některá předchozí hodina).\n", + "\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
movie_idtitleactor_idnameididecko_filmu
01Vykoupení z věznice Shawshank1Tim Robbins11
11Vykoupení z věznice Shawshank2Morgan Freeman21
25Sedm2Morgan Freeman25
320Temný rytíř2Morgan Freeman220
464Million Dollar Baby2Morgan Freeman264
.....................
9806300Píseň moře7523Jon Kenny7523300
9807300Píseň moře7524Lisa Hannigan7524300
9808300Píseň moře7525Lucy O'Connell7525300
9809300Píseň moře7526Paul Young7526300
9810300Píseň moře7527Grethe Mogensen7527300
\n", + "

9811 rows × 6 columns

\n", + "
" + ], + "text/plain": [ + " movie_id title actor_id name \\\n", + "0 1 Vykoupení z věznice Shawshank 1 Tim Robbins \n", + "1 1 Vykoupení z věznice Shawshank 2 Morgan Freeman \n", + "2 5 Sedm 2 Morgan Freeman \n", + "3 20 Temný rytíř 2 Morgan Freeman \n", + "4 64 Million Dollar Baby 2 Morgan Freeman \n", + "... ... ... ... ... \n", + "9806 300 Píseň moře 7523 Jon Kenny \n", + "9807 300 Píseň moře 7524 Lisa Hannigan \n", + "9808 300 Píseň moře 7525 Lucy O'Connell \n", + "9809 300 Píseň moře 7526 Paul Young \n", + "9810 300 Píseň moře 7527 Grethe Mogensen \n", + "\n", + " id idecko_filmu \n", + "0 1 1 \n", + "1 2 1 \n", + "2 2 5 \n", + "3 2 20 \n", + "4 2 64 \n", + "... ... ... \n", + "9806 7523 300 \n", + "9807 7524 300 \n", + "9808 7525 300 \n", + "9809 7526 300 \n", + "9810 7527 300 \n", + "\n", + "[9811 rows x 6 columns]" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.read_sql_query('''\n", + " SELECT movie_id, title, actor_id, name, a.id, m.id AS idecko_filmu\n", + " FROM actors AS a\n", + " LEFT JOIN movie_to_actor AS ma ON a.id = ma.actor_id\n", + " LEFT JOIN movies AS m ON m.id = ma.movie_id\n", + "''', engine)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## CREATE TABLE\n", + "\n", + "Pokud budeme chtít vytvořit novou tabulku, používá se k tomu příkaz CREATE TABLE.\n", + "Musíme vyjmenovat názvy a typy sloupců, které v tabulce chceme mít." + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "ename": "OperationalError", + "evalue": "(sqlite3.OperationalError) database is locked\n[SQL: \n CREATE TABLE phonebook (\n id INT PRIMARY KEY,\n name VARCHAR,\n phone_number VARCHAR\n ) \n]\n(Background on this error at: http://sqlalche.me/e/e3q8)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mOperationalError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sqlalchemy/engine/base.py\u001b[0m in \u001b[0;36m_execute_context\u001b[0;34m(self, dialect, constructor, statement, parameters, *args)\u001b[0m\n\u001b[1;32m 1245\u001b[0m self.dialect.do_execute(\n\u001b[0;32m-> 1246\u001b[0;31m \u001b[0mcursor\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstatement\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparameters\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcontext\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1247\u001b[0m )\n", + "\u001b[0;32m/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sqlalchemy/engine/default.py\u001b[0m in \u001b[0;36mdo_execute\u001b[0;34m(self, cursor, statement, parameters, context)\u001b[0m\n\u001b[1;32m 587\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdo_execute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcursor\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstatement\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparameters\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcontext\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 588\u001b[0;31m \u001b[0mcursor\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexecute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstatement\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparameters\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 589\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mOperationalError\u001b[0m: database is locked", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[0;31mOperationalError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mphone_number\u001b[0m \u001b[0mVARCHAR\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m ) \n\u001b[0;32m----> 7\u001b[0;31m ''')\n\u001b[0m", + "\u001b[0;32m/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sqlalchemy/engine/base.py\u001b[0m in \u001b[0;36mexecute\u001b[0;34m(self, statement, *multiparams, **params)\u001b[0m\n\u001b[1;32m 2180\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2181\u001b[0m \u001b[0mconnection\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_contextual_connect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mclose_with_result\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2182\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mconnection\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexecute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstatement\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0mmultiparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2183\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2184\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mscalar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstatement\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0mmultiparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sqlalchemy/engine/base.py\u001b[0m in \u001b[0;36mexecute\u001b[0;34m(self, object_, *multiparams, **params)\u001b[0m\n\u001b[1;32m 974\u001b[0m \"\"\"\n\u001b[1;32m 975\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobject_\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mutil\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstring_types\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 976\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_execute_text\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobject_\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmultiparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 977\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 978\u001b[0m \u001b[0mmeth\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mobject_\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_execute_on_connection\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sqlalchemy/engine/base.py\u001b[0m in \u001b[0;36m_execute_text\u001b[0;34m(self, statement, multiparams, params)\u001b[0m\n\u001b[1;32m 1147\u001b[0m \u001b[0mparameters\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1148\u001b[0m \u001b[0mstatement\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1149\u001b[0;31m \u001b[0mparameters\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1150\u001b[0m )\n\u001b[1;32m 1151\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_has_events\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mengine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_has_events\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sqlalchemy/engine/base.py\u001b[0m in \u001b[0;36m_execute_context\u001b[0;34m(self, dialect, constructor, statement, parameters, *args)\u001b[0m\n\u001b[1;32m 1248\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mBaseException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1249\u001b[0m self._handle_dbapi_exception(\n\u001b[0;32m-> 1250\u001b[0;31m \u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstatement\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparameters\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcursor\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcontext\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1251\u001b[0m )\n\u001b[1;32m 1252\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sqlalchemy/engine/base.py\u001b[0m in \u001b[0;36m_handle_dbapi_exception\u001b[0;34m(self, e, statement, parameters, cursor, context)\u001b[0m\n\u001b[1;32m 1474\u001b[0m \u001b[0mutil\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mraise_from_cause\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnewraise\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mexc_info\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1475\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mshould_wrap\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1476\u001b[0;31m \u001b[0mutil\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mraise_from_cause\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msqlalchemy_exception\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mexc_info\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1477\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1478\u001b[0m \u001b[0mutil\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreraise\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mexc_info\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sqlalchemy/util/compat.py\u001b[0m in \u001b[0;36mraise_from_cause\u001b[0;34m(exception, exc_info)\u001b[0m\n\u001b[1;32m 396\u001b[0m \u001b[0mexc_type\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mexc_value\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mexc_tb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mexc_info\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 397\u001b[0m \u001b[0mcause\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mexc_value\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mexc_value\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mexception\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 398\u001b[0;31m \u001b[0mreraise\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexception\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mexception\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtb\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mexc_tb\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcause\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcause\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 399\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 400\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sqlalchemy/util/compat.py\u001b[0m in \u001b[0;36mreraise\u001b[0;34m(tp, value, tb, cause)\u001b[0m\n\u001b[1;32m 150\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__cause__\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcause\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 151\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__traceback__\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mtb\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 152\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_traceback\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtb\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 153\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 154\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sqlalchemy/engine/base.py\u001b[0m in \u001b[0;36m_execute_context\u001b[0;34m(self, dialect, constructor, statement, parameters, *args)\u001b[0m\n\u001b[1;32m 1244\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mevt_handled\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1245\u001b[0m self.dialect.do_execute(\n\u001b[0;32m-> 1246\u001b[0;31m \u001b[0mcursor\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstatement\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparameters\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcontext\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1247\u001b[0m )\n\u001b[1;32m 1248\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mBaseException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sqlalchemy/engine/default.py\u001b[0m in \u001b[0;36mdo_execute\u001b[0;34m(self, cursor, statement, parameters, context)\u001b[0m\n\u001b[1;32m 586\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 587\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdo_execute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcursor\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstatement\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparameters\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcontext\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 588\u001b[0;31m \u001b[0mcursor\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexecute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstatement\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparameters\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 589\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 590\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdo_execute_no_params\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcursor\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstatement\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcontext\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mOperationalError\u001b[0m: (sqlite3.OperationalError) database is locked\n[SQL: \n CREATE TABLE phonebook (\n id INT PRIMARY KEY,\n name VARCHAR,\n phone_number VARCHAR\n ) \n]\n(Background on this error at: http://sqlalche.me/e/e3q8)" + ] + } + ], "source": [ - "## CREATE TABLE" + "try:\n", + " engine.execute('''\n", + " CREATE TABLE phonebook (\n", + " id INT PRIMARY KEY,\n", + " name VARCHAR,\n", + " phone_number VARCHAR\n", + " ) \n", + " ''')\n", + "except OperationalError as e:\n", + " if str(e) == 'database is locked':\n", + " print('Zkus zabit kernel a znovu spustit primo tento prikaz :/ Me')" ] }, { @@ -1535,7 +2401,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.3" + "version": "3.7.6" } }, "nbformat": 4,