diff --git a/lessons/pydata/databases/index.ipynb b/lessons/pydata/databases/index.ipynb new file mode 100644 index 0000000000..01f56fc6b9 --- /dev/null +++ b/lessons/pydata/databases/index.ipynb @@ -0,0 +1,1543 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Databáze" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Obsah:\n", + "\n", + "- Úvod do databází\n", + "- Úvod do relačních databází\n", + "- Úvod do SQL + Python a Pandas" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Úvod do databází" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Doteď jste na kurzu zřejmě pracovali se **soubory** - odněkud soubor stáhli na svůj počítač, a tam ho zpracovali, a pak třeba zase výsledek někam nahráli. Tento postup ale nestačí, pokud s těmito daty potřebuje pracovat více lidí (nebo strojů) najednou a zároveň je i aktualizovat. To se řeší tak, že spustíte **databázový systém** (DBMS, [SŘBD](https://cs.wikipedia.org/wiki/Syst%C3%A9m_%C5%99%C3%ADzen%C3%AD_b%C3%A1ze_dat)), ten ta data u sebe spravuje (soubory na disku obsahující specializované datové struktury) a vy se na tento systém připojujete přes počítačovou síť. Nebo třeba používáte webovou aplikaci a ta je na tento databázový systém (databázi) připojena.\n", + "\n", + "Např. e-shop bude pracovat s databází, ve které jsou uloženy informace o prodávaném zboží, rozdělení zboží do kategorií, objednávky, reklamace, registrovaní uživatelé... Takovou databázi můžeme označit za \"transakční\".\n", + "\n", + "Vy jako datoví analytici, inženýři apod. se pravděpodobně budete chtít do takovéto databáze připojit a stáhnout si z ní část dat pro svou další práci. Nebo dokonce může být vaším úkolem vytvořit novou \"analytickou\" databázi, která obsahuje data v jiné podobě, např. prodávané zboží bez popisků, bez fotografií, ale zato se statistikami návštěvnosti a prodejnosti.\n", + "\n", + "V těchto materiálech budeme pracovat s databází [SQLite](https://www.sqlite.org/). Ta je poněkud specifická tím, že je uložena v jednom souboru (s příponou `.sqlite` nebo `.db`), není to tedy samostatně běžící server, ke kterému byste se připojovali, jak je tomu u většiny databází. O to snadněji se ale s SQLite pracuje. I SQLite umožňuje pracovat s jednou databází (jedním souborem) z několika programů zároveň, narozdíl od např. CSV nebo XLS sobourů." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Vlastnosti databází\n", + "\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", + "- 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", + "- Š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", + " \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", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Relační databáze\n", + "\n", + "Jde o typickou, klasickou, nejčastěji používanou kategorii databázových systémů. Používají se od 70. let, existuje okolo nich široký ekosystém se spoustou nástrojů a také lidí, kteří s nimi umí pracovat.\n", + "\n", + "Co [relační databáze](https://en.wikipedia.org/wiki/Relational_database) obsahuje:\n", + "\n", + "- \"databáze\" (jeden databázový systém může spravovat několik databází)\n", + " - uživatelé (users)\n", + " - **tabulky**\n", + " - **sloupce**\n", + " - indexy\n", + " - constraints\n", + " - cizí klíče (foreign keys)\n", + " - triggery\n", + " - pohledy (views)\n", + " - procedury\n", + " - sekvence\n", + "\n", + "Data se ukládají v podobě řádek a sloupců do jednotlivých tabulek:\n", + "\n", + "| title | year | director_name | director_birthdate |\n", + "|:----------------------|:-----|:----------------|:-------------------|\n", + "| Pelíšky | 1999 | Jan Hřebejk | 1967-06-27 |\n", + "| Forrest Gump | 1994 | Robert Zemeckis | 1951-05-14 |\n", + "| Návrat do budoucnosti | 1985 | Robert Zemeckis | 1951-05-14 |\n", + "\n", + "Každý řádek je označen svým unikátním identifikátorem, a duplicitní data se *normalizují*:\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", + "\n", + "| director_id | name | birthdate |\n", + "|-------------|:----------------|------------|\n", + "| 1 | Jan Hřebejk | 1967-06-27 |\n", + "| 2 | Robert Zemeckis | 1951-05-14 |\n", + "\n", + "Vztah mezi režiséry a filmy je zde 1:N. Každý jeden režisér je provázán s několika filmy. Každý jeden film je provázán s jedním režisérem (a nebo žádným, pokud jeho director_id není vyplněno).\n", + "\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", + "\n", + "| director_id | name | birthdate |\n", + "|-------------|:----------------|------------|\n", + "| 1 | Jan Hřebejk | 1967-06-27 |\n", + "| 2 | Robert Zemeckis | 1951-05-14 |\n", + "| 3 | Joe Smith | 1950-01-01 |\n", + "\n", + "| movie_id | director_id |\n", + "|----------|-------------|\n", + "| 1 | 1 |\n", + "| 2 | 2 |\n", + "| 3 | 2 |\n", + "| 3 | 3 | \n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## SQL\n", + "\n", + "SQL je jazyk, kterým komunikujeme s relační databází. Umí vyjádřit různé operace nad tabulkami - výběr sloupců, řádků, vztahy mezi více tabulkami, agregace hodnot z více řádků... (Nepřípomíná vám to něco? Pandas DataFrame? :) )\n", + "\n", + "Příklad:\n", + "\n", + "```\n", + "SELECT title, year FROM movies;\n", + "\n", + "UPDATE directors SET birthdate = \"1950-01-02\" WHERE director_id = 3;\n", + "```\n", + "\n", + "Dokonce i jiný software, než jsou relační databáze, rozumí SQL. Často právě analytické nástroje, data lakes, Amazon S3... Pak existuje spousta databází a jazyků, které se jazykem SQL inspirovaly - např. databáze Cassandra a její jazyk CQL.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instalace a import SQLAlchemy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Každá databáze se z Pythonu používá trochu jinak - liší se název modulu, který je potřeba importovat, mírně se liší způsob předávání dat použitých v SQL dotazech, liší se forma dat vrácených ve výsledku... Použijeme proto knihovnu [SQLAlchemy](https://www.sqlalchemy.org/), která tyto detaily _abstrahuje_ a poskytuje rozhraní stejné pro všechny databáze (které SQLAlchemy podporuje).\n", + "\n", + "SQLAlchemy se skládá ze [dvou částí](https://docs.sqlalchemy.org/en/13/):\n", + "\n", + "- Core - to je právě ta zmíněná abstrakce základních operací s databází, tuto část budeme používat\n", + " - engine, connections, transactions\n", + " - table metadata\n", + " - SQL expression language\n", + "- [ORM](https://docs.sqlalchemy.org/en/13/orm/tutorial.html) - umožňuje pracovat s daty v databázi prostřednistvím mapování na objekty\n", + " - zajímavé hlavně při psaní větších aplikací (webových aplikací apod.)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Instalaci knihovny [SQLAlchemy](https://www.sqlalchemy.org/) provedeme přes pip (nezapomeňte mít aktivovaný venv, do kterého to chcete instalovat):\n", + "\n", + "```\n", + "pip install sqlalchemy\n", + "```\n", + "\n", + "Případně lze instalaci spustit přímo z Jupyteru:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: sqlalchemy in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (1.3.13)\n", + "Note: you may need to restart the kernel to use updated packages.\n" + ] + } + ], + "source": [ + "%pip install sqlalchemy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Knihovnu SQLAlchemy naimportujeme:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import sqlalchemy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Jako vždy, naimportujeme i [Pandas](https://pandas.pydata.org/pandas-docs/stable/reference/index.html):" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Stažení filmové databáze\n", + "\n", + "Pro ukázku práce s databází použijeme data od Míry Brabence.\n", + "Jde o databázi typu [SQLite](https://cs.wikipedia.org/wiki/SQLite) - skládá se z jediného souboru, ve kterém jsou všecha data. To znamená, že není žádný velký server, ke kterému byste se připojovaly jménem a heslem, jako u \"klasických\" databází (PostgreSQL, Oracle, MS SQL...).\n", + "Databáze v podobě SQLite souboru má výhodu v tom, že když něco rozbijete, tak ten soubor prostě smažete a uděláte si nový :)\n", + "\n", + "Soubor s databází stáhneme knihovnou [Requests](https://requests.readthedocs.io/en/master/), kterou už máte nainstalovanou (instrukce byly v první hodině)\n", + "a uložíme ho do souboru v pracovním adresáři, tj. tam, odkud jste spustili Jupyter Notebook." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "import requests" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1421312" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "db_data = requests.get('https://github.com/messa/movie-db-2020/raw/master/movies.sqlite').content\n", + "Path('movies.sqlite').write_bytes(db_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Otevření databáze, průzkum struktury" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "engine = sqlalchemy.create_engine('sqlite:///movies.sqlite')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Objekt `engine` obsahuje připojení do databáze a skrz něj budeme provádět operace s danou databází.\n", + "\n", + "Začneme tím, že se podíváme, jaká je struktura té databáze - jaké tabulky obsahuje a co obsahují ty tabulky. Každá databáze na to má jiné finty, jak toto zjistit (někdy funguje SQL příkaz `SHOW TABLES`, jindy je zase potřeba `SELECT` z metadat), naštěstí SQLAlchemy nám s tím pomůže." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['actors', 'movie_to_actor', 'movies']" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sqlalchemy.inspect(engine).get_table_names()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def prozkoumat(engine):\n", + " inspector = sqlalchemy.inspect(engine)\n", + " for schema in inspector.get_schema_names():\n", + " print('Schema:', schema)\n", + " for table_name in inspector.get_table_names(schema=schema):\n", + " print()\n", + " print(' Table:', table_name)\n", + " print()\n", + " for column in inspector.get_columns(table_name, schema=schema):\n", + " print(' Column:', column['name'].ljust(12), column['type'])" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Schema: main\n", + "\n", + " Table: actors\n", + "\n", + " Column: id INTEGER\n", + " Column: csfd_url VARCHAR\n", + " Column: name VARCHAR\n", + " Column: birth_date DATE\n", + "\n", + " Table: movie_to_actor\n", + "\n", + " Column: id INTEGER\n", + " Column: movie_id INTEGER\n", + " Column: actor_id INTEGER\n", + "\n", + " Table: movies\n", + "\n", + " Column: id INTEGER\n", + " Column: title VARCHAR\n", + " Column: csfd_url VARCHAR\n", + " Column: year INTEGER\n", + " Column: rating NUMERIC\n" + ] + } + ], + "source": [ + "prozkoumat(engine)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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": [ + "## SELECT\n", + "\n", + "Ukážeme si několik způsobů, jak data z databáze \"vytáhnout\" do Pythonu." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "engine.execute('SELECT id, name, birth_date FROM actors')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Výsledkem volání `engine.execute(...)` je objekt, který umí reprezentuje výsledek SQL dotazu. V případě SELECT se skrz tento objekt dají procházet získané řádky, v případě operací INSERT, UPDATE, DELETE tento objekt obsahuje např. počet změněných řádek.\n", + "\n", + "Zkusíme si zobrazit jednotlivé řádky. LIMIT slouží k omezení počtu vracených záznamů." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "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 id, name, birth_date FROM actors LIMIT 5')\n", + "for row in result:\n", + " print(row)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Zdálo by se, že procházení `result` vrací n-tice (tuple), ale není tomu tak." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "\n", + "\n", + "\n" + ] + } + ], + "source": [ + "result = engine.execute('SELECT id, name, birth_date FROM actors LIMIT 5')\n", + "for row in result:\n", + " print(type(row))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "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" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "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" + ] + } + ], + "source": [ + "result = engine.execute('SELECT id, name, csfd_url FROM actors LIMIT 5')\n", + "for row in result:\n", + " print(row[0], row[1])" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "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" + ] + } + ], + "source": [ + "result = engine.execute('SELECT id, name, csfd_url FROM actors LIMIT 5')\n", + "for row in result:\n", + " print(row['id'], row['name'])" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "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" + ] + } + ], + "source": [ + "result = engine.execute('SELECT id, name, csfd_url FROM actors LIMIT 5')\n", + "for row in result:\n", + " print(dict(row))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Pokud chceme získat hodnoty ze všech sloupečků, použijeme hvězdičku." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'id': 1, 'csfd_url': 'https://www.csfd.cz/tvurce/103-tim-robbins/', 'name': 'Tim Robbins', 'birth_date': '1958-10-16'}\n", + "{'id': 2, 'csfd_url': 'https://www.csfd.cz/tvurce/92-morgan-freeman/', 'name': 'Morgan Freeman', 'birth_date': '1937-06-01'}\n", + "{'id': 3, 'csfd_url': 'https://www.csfd.cz/tvurce/202-bob-gunton/', 'name': 'Bob Gunton', 'birth_date': '1945-11-15'}\n", + "{'id': 4, 'csfd_url': 'https://www.csfd.cz/tvurce/203-william-sadler/', 'name': 'William Sadler', 'birth_date': '1950-04-13'}\n", + "{'id': 5, 'csfd_url': 'https://www.csfd.cz/tvurce/204-clancy-brown/', 'name': 'Clancy Brown', 'birth_date': '1959-01-05'}\n" + ] + } + ], + "source": [ + "result = engine.execute('SELECT * FROM actors LIMIT 5')\n", + "for row in result:\n", + " print(dict(row))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Z dat lze vytvořit i Pandas DataFrame:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "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", + "
idname
01Tim Robbins
12Morgan Freeman
23Bob Gunton
34William Sadler
45Clancy Brown
\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" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.read_sql_query('SELECT id, name FROM actors LIMIT 5', engine)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Toto je zkratka pro načtení celé tabulky:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "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", + "
idcsfd_urlnamebirth_date
01https://www.csfd.cz/tvurce/103-tim-robbins/Tim Robbins1958-10-16
12https://www.csfd.cz/tvurce/92-morgan-freeman/Morgan Freeman1937-06-01
23https://www.csfd.cz/tvurce/202-bob-gunton/Bob Gunton1945-11-15
34https://www.csfd.cz/tvurce/203-william-sadler/William Sadler1950-04-13
45https://www.csfd.cz/tvurce/204-clancy-brown/Clancy Brown1959-01-05
...............
75227523https://www.csfd.cz/tvurce/147104-jon-kenny/Jon KennyNaT
75237524https://www.csfd.cz/tvurce/147105-lisa-hannigan/Lisa Hannigan1981-02-12
75247525https://www.csfd.cz/tvurce/162204-lucy-o-connell/Lucy O'ConnellNaT
75257526https://www.csfd.cz/tvurce/309228-paul-young/Paul YoungNaT
75267527https://www.csfd.cz/tvurce/458624-grethe-mogen...Grethe Mogensen1937-05-25
\n", + "

7527 rows × 4 columns

\n", + "
" + ], + "text/plain": [ + " 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 NaT \n", + "7523 Lisa Hannigan 1981-02-12 \n", + "7524 Lucy O'Connell NaT \n", + "7525 Paul Young NaT \n", + "7526 Grethe Mogensen 1937-05-25 \n", + "\n", + "[7527 rows x 4 columns]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.read_sql_table('actors', engine)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Průzkum dat ve filmové databázi\n", + "\n", + "Data z jednotlivých tabulek si nahrajeme do Pandas DataFramů, se kterými budeme dále pracovat.\n", + "\n", + "Pro přehlednost si zde vypíšeme ukázku obsahu těch DataFramů, abychom věděli, s čím pracujeme." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['actors', 'movie_to_actor', 'movies']" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sqlalchemy.inspect(engine).get_table_names()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "actors = pd.read_sql_table('actors', engine)\n", + "movies = pd.read_sql_table('movies', engine)\n", + "movie_to_actor = pd.read_sql_table('movie_to_actor', engine)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "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", + "
idcsfd_urlnamebirth_date
01https://www.csfd.cz/tvurce/103-tim-robbins/Tim Robbins1958-10-16
12https://www.csfd.cz/tvurce/92-morgan-freeman/Morgan Freeman1937-06-01
23https://www.csfd.cz/tvurce/202-bob-gunton/Bob Gunton1945-11-15
34https://www.csfd.cz/tvurce/203-william-sadler/William Sadler1950-04-13
45https://www.csfd.cz/tvurce/204-clancy-brown/Clancy Brown1959-01-05
\n", + "
" + ], + "text/plain": [ + " id csfd_url name \\\n", + "0 1 https://www.csfd.cz/tvurce/103-tim-robbins/ Tim Robbins \n", + "1 2 https://www.csfd.cz/tvurce/92-morgan-freeman/ Morgan Freeman \n", + "2 3 https://www.csfd.cz/tvurce/202-bob-gunton/ Bob Gunton \n", + "3 4 https://www.csfd.cz/tvurce/203-william-sadler/ William Sadler \n", + "4 5 https://www.csfd.cz/tvurce/204-clancy-brown/ Clancy Brown \n", + "\n", + " birth_date \n", + "0 1958-10-16 \n", + "1 1937-06-01 \n", + "2 1945-11-15 \n", + "3 1950-04-13 \n", + "4 1959-01-05 " + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "actors.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "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", + "
idtitlecsfd_urlyearrating
01Vykoupení z věznice Shawshankhttps://www.csfd.cz/film/2294-vykoupeni-z-vezn...199495.3
12Forrest Gumphttps://www.csfd.cz/film/10135-forrest-gump/199494.5
23Zelená mílehttps://www.csfd.cz/film/2292-zelena-mile/199992.8
34Přelet nad kukaččím hnízdemhttps://www.csfd.cz/film/2982-prelet-nad-kukac...197592.5
45Sedmhttps://www.csfd.cz/film/2671-sedm/199592.4
\n", + "
" + ], + "text/plain": [ + " id title \\\n", + "0 1 Vykoupení z věznice Shawshank \n", + "1 2 Forrest Gump \n", + "2 3 Zelená míle \n", + "3 4 Přelet nad kukaččím hnízdem \n", + "4 5 Sedm \n", + "\n", + " csfd_url year rating \n", + "0 https://www.csfd.cz/film/2294-vykoupeni-z-vezn... 1994 95.3 \n", + "1 https://www.csfd.cz/film/10135-forrest-gump/ 1994 94.5 \n", + "2 https://www.csfd.cz/film/2292-zelena-mile/ 1999 92.8 \n", + "3 https://www.csfd.cz/film/2982-prelet-nad-kukac... 1975 92.5 \n", + "4 https://www.csfd.cz/film/2671-sedm/ 1995 92.4 " + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "movies.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "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", + "
idmovie_idactor_id
0111
1212
2313
3414
4515
\n", + "
" + ], + "text/plain": [ + " id movie_id actor_id\n", + "0 1 1 1\n", + "1 2 1 2\n", + "2 3 1 3\n", + "3 4 1 4\n", + "4 5 1 5" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "movie_to_actor.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## SELECT ... WHERE ... AND/OR" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[(4849, 'https://www.csfd.cz/tvurce/39309-medved-bart-2/', 'medvěd Bart 2', '2000-01-20'),\n", + " (5703, 'https://www.csfd.cz/tvurce/283519-zaira-wasim/', 'Zaira Wasim', '2000-10-23'),\n", + " (6290, 'https://www.csfd.cz/tvurce/35296-morgan-lily/', 'Morgan Lily', '2000-04-11')]" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(engine.execute('SELECT * FROM actors WHERE birth_date > \"2000-01-01\" AND birth_date < \"2001-01-01\"'))" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "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", + "
idcsfd_urlnamebirth_date
48484849https://www.csfd.cz/tvurce/39309-medved-bart-2/medvěd Bart 22000-01-20
57025703https://www.csfd.cz/tvurce/283519-zaira-wasim/Zaira Wasim2000-10-23
62896290https://www.csfd.cz/tvurce/35296-morgan-lily/Morgan Lily2000-04-11
\n", + "
" + ], + "text/plain": [ + " id csfd_url name \\\n", + "4848 4849 https://www.csfd.cz/tvurce/39309-medved-bart-2/ medvěd Bart 2 \n", + "5702 5703 https://www.csfd.cz/tvurce/283519-zaira-wasim/ Zaira Wasim \n", + "6289 6290 https://www.csfd.cz/tvurce/35296-morgan-lily/ Morgan Lily \n", + "\n", + " birth_date \n", + "4848 2000-01-20 \n", + "5702 2000-10-23 \n", + "6289 2000-04-11 " + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "actors[(actors['birth_date'] > '2000-01-01') & (actors['birth_date'] < '2001-01-01')]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## SELECT ... ORDER BY" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[(526, 'https://www.csfd.cz/tvurce/239127-noah-jupe/', 'Noah Jupe', '2005-02-25'),\n", + " (7051, 'https://www.csfd.cz/tvurce/321955-rocco-lerro/', 'Rocco Lerro', '2005-08-21'),\n", + " (4979, 'https://www.csfd.cz/tvurce/357987-ariana-greenblatt/', 'Ariana Greenblatt', '2007-08-27'),\n", + " (1876, 'https://www.csfd.cz/tvurce/540779-hailey-hermida/', 'Hailey Hermida', '2007-09-13'),\n", + " (1865, 'https://www.csfd.cz/tvurce/354371-pierce-pope/', 'Pierce Pope', '2008-06-02')]" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(engine.execute('SELECT * FROM actors WHERE birth_date > \"2005-01-01\" ORDER BY birth_date ASC'))" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "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", + "
idcsfd_urlnamebirth_date
525526https://www.csfd.cz/tvurce/239127-noah-jupe/Noah Jupe2005-02-25
70507051https://www.csfd.cz/tvurce/321955-rocco-lerro/Rocco Lerro2005-08-21
49784979https://www.csfd.cz/tvurce/357987-ariana-green...Ariana Greenblatt2007-08-27
18751876https://www.csfd.cz/tvurce/540779-hailey-hermida/Hailey Hermida2007-09-13
18641865https://www.csfd.cz/tvurce/354371-pierce-pope/Pierce Pope2008-06-02
\n", + "
" + ], + "text/plain": [ + " id csfd_url \\\n", + "525 526 https://www.csfd.cz/tvurce/239127-noah-jupe/ \n", + "7050 7051 https://www.csfd.cz/tvurce/321955-rocco-lerro/ \n", + "4978 4979 https://www.csfd.cz/tvurce/357987-ariana-green... \n", + "1875 1876 https://www.csfd.cz/tvurce/540779-hailey-hermida/ \n", + "1864 1865 https://www.csfd.cz/tvurce/354371-pierce-pope/ \n", + "\n", + " name birth_date \n", + "525 Noah Jupe 2005-02-25 \n", + "7050 Rocco Lerro 2005-08-21 \n", + "4978 Ariana Greenblatt 2007-08-27 \n", + "1875 Hailey Hermida 2007-09-13 \n", + "1864 Pierce Pope 2008-06-02 " + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "actors[(actors['birth_date'] > '2005-01-01')].sort_values('birth_date')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## SELECT ... GROUP BY" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "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)]" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(engine.execute('SELECT year, COUNT(*) FROM movies GROUP BY year HAVING COUNT(*) > 5'))" + ] + }, + { + "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", + "metadata": {}, + "source": [ + "## CREATE TABLE" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## INSERT" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## UPDATE" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## DELETE" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Závěr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Odkazy\n", + "\n", + "https://naucse.python.cz/2019/brno-podzim-2019-ut/beginners/database/\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/lessons/pydata/databases/info.yml b/lessons/pydata/databases/info.yml new file mode 100644 index 0000000000..8469131cfe --- /dev/null +++ b/lessons/pydata/databases/info.yml @@ -0,0 +1,4 @@ +title: Databáze a SQL +style: ipynb +attribution: Pro PyDataCZ napsal Petr Messner, 2020. +license: cc-by-sa-40 diff --git a/lessons/pydata/databases/movies.sqlite b/lessons/pydata/databases/movies.sqlite new file mode 100644 index 0000000000..f59e2dd7a0 Binary files /dev/null and b/lessons/pydata/databases/movies.sqlite differ