{"cells": [{"cell_type": "markdown", "metadata": {}, "source": ["# SQL Magic Commands with SQLite in a Notebook\n", "\n", "SQL from a notebooks, using magic commands to query a *sqllite3* database."]}, {"cell_type": "code", "execution_count": 1, "metadata": {"collapsed": true}, "outputs": [], "source": ["%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "plt.style.use('ggplot')"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This notebook introduced some of the magic commands used to easily query a SQLite database with [sqlite3](https://docs.python.org/3.4/library/sqlite3.html). SQLite databases can be easily manipulated with open source tools such as [SQLite Manager](https://addons.mozilla.org/fr/firefox/addon/sqlite-manager/) (add-on for [firefox](https://www.mozilla.org/)) or [SQLiteSpy](http://www.yunqa.de/delphi/doku.php/products/sqlitespy/index) (only on Windows). However, it is very convenient to put the results of a SQL query into a [DataFrame](http://pandas.pydata.org/pandas-docs/dev/generated/pandas.DataFrame.html). That what's this notebook is about.\n", "\n", "Let's start by importing some data."]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [{"data": {"text/plain": ["['.\\\\velib_vanves.txt']"]}, "execution_count": 3, "metadata": {}, "output_type": "execute_result"}], "source": ["import pyensae\n", "import pyensae.datasource\n", "%load_ext pyensae\n", "pyensae.datasource.download_data(\"velib_vanves.zip\", website = \"xd\")"]}, {"cell_type": "code", "execution_count": 3, "metadata": {"collapsed": true}, "outputs": [], "source": ["import os\n", "if os.path.exists(\"notebook_example.db3\"):\n", " os.remove(\"notebook_example.db3\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We connect to the database:"]}, {"cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [{"data": {"text/plain": [""]}, "execution_count": 5, "metadata": {}, "output_type": "execute_result"}], "source": ["%SQL_connect notebook_example.db3"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The database is empty so the table list should be empty:"]}, {"cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [{"data": {"text/plain": ["[]"]}, "execution_count": 6, "metadata": {}, "output_type": "execute_result"}], "source": ["%SQL_tables"]}, {"cell_type": "markdown", "metadata": {}, "source": ["So we import a flat file (TSV format only) into the database."]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [{"data": {"text/plain": ["9461"]}, "execution_count": 7, "metadata": {}, "output_type": "execute_result"}], "source": ["%SQL_import_tsv -t velib velib_vanves.txt"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We check there is one more table:"]}, {"cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [{"data": {"text/plain": ["['velib']"]}, "execution_count": 8, "metadata": {}, "output_type": "execute_result"}], "source": ["%SQL_tables"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We get the schema of the database:"]}, {"cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [{"data": {"text/plain": ["{0: ('address', str),\n", " 1: ('available_bike_stands', int),\n", " 2: ('available_bikes', int),\n", " 3: ('banking', int),\n", " 4: ('bike_stands', int),\n", " 5: ('bonus', int),\n", " 6: ('contract_name', str),\n", " 7: ('last_update', str),\n", " 8: ('lat', str),\n", " 9: ('lng', str),\n", " 10: ('name', str),\n", " 11: ('number', int),\n", " 12: ('status', str),\n", " 13: ('idr', int)}"]}, "execution_count": 9, "metadata": {}, "output_type": "execute_result"}], "source": ["%SQL_schema velib"]}, {"cell_type": "markdown", "metadata": {}, "source": ["And we execute the first query:"]}, {"cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
MAX(available_bike_stands +available_bikes)
071
\n", "
"], "text/plain": [" MAX(available_bike_stands +available_bikes)\n", "0 71"]}, "execution_count": 10, "metadata": {}, "output_type": "execute_result"}], "source": ["%%SQL \n", "SELECT MAX(available_bike_stands +available_bikes) FROM velib"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Or another in one row:"]}, {"cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
COUNT(*)
09461
\n", "
"], "text/plain": [" COUNT(*)\n", "0 9461"]}, "execution_count": 11, "metadata": {}, "output_type": "execute_result"}], "source": ["%SQL -q \"SELECT COUNT(*) FROM velib\""]}, {"cell_type": "markdown", "metadata": {}, "source": ["We want to draw a random sample out of this table. We ask the database to recognize the following python function (its name cannot contain ``'_'``):"]}, {"cell_type": "code", "execution_count": 11, "metadata": {"collapsed": true}, "outputs": [], "source": ["import random\n", "def arandomfunction():\n", " return random.randint(1,100)\n", "%SQL_add_function arandomfunction"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We then execute the following query. Because the first line contains a identifier, the query will only display the shape of the results dataframe and not its content which will be stored in ``df``:"]}, {"cell_type": "code", "execution_count": 12, "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
addressavailable_bike_standsavailable_bikesbankingbike_standsbonuscontract_namelast_updatelatlngnamenumberstatusidrrnd
0112 RUE VERCINGETORIX - 75014 PARIS6610670Paris15/07/2013 16:4048,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN2524958
1112 RUE VERCINGETORIX - 75014 PARIS53140670Paris15/07/2013 22:2048,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN10882176
2112 RUE VERCINGETORIX - 75014 PARIS6160670Paris16/07/2013 13:5048,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN33741517
3112 RUE VERCINGETORIX - 75014 PARIS6160670Paris16/07/2013 14:1548,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN34356060
4112 RUE VERCINGETORIX - 75014 PARIS6160670Paris17/07/2013 04:0548,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN54757420
5112 RUE VERCINGETORIX - 75014 PARIS6160670Paris17/07/2013 14:1048,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN69628310
6112 RUE VERCINGETORIX - 75014 PARIS6160670Paris18/07/2013 02:0548,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN87203089
7112 RUE VERCINGETORIX - 75014 PARIS6160670Paris18/07/2013 03:3048,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN8929238
8112 RUE VERCINGETORIX - 75014 PARIS6160670Paris18/07/2013 03:4048,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN89538142
9112 RUE VERCINGETORIX - 75014 PARIS6160670Paris18/07/2013 07:4548,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN95560215
\n", "
"], "text/plain": [" address available_bike_stands \\\n", "0 112 RUE VERCINGETORIX - 75014 PARIS 66 \n", "1 112 RUE VERCINGETORIX - 75014 PARIS 53 \n", "2 112 RUE VERCINGETORIX - 75014 PARIS 61 \n", "3 112 RUE VERCINGETORIX - 75014 PARIS 61 \n", "4 112 RUE VERCINGETORIX - 75014 PARIS 61 \n", "5 112 RUE VERCINGETORIX - 75014 PARIS 61 \n", "6 112 RUE VERCINGETORIX - 75014 PARIS 61 \n", "7 112 RUE VERCINGETORIX - 75014 PARIS 61 \n", "8 112 RUE VERCINGETORIX - 75014 PARIS 61 \n", "9 112 RUE VERCINGETORIX - 75014 PARIS 61 \n", "\n", " available_bikes banking bike_stands bonus contract_name \\\n", "0 1 0 67 0 Paris \n", "1 14 0 67 0 Paris \n", "2 6 0 67 0 Paris \n", "3 6 0 67 0 Paris \n", "4 6 0 67 0 Paris \n", "5 6 0 67 0 Paris \n", "6 6 0 67 0 Paris \n", "7 6 0 67 0 Paris \n", "8 6 0 67 0 Paris \n", "9 6 0 67 0 Paris \n", "\n", " last_update lat lng name \\\n", "0 15/07/2013 16:40 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "1 15/07/2013 22:20 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "2 16/07/2013 13:50 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "3 16/07/2013 14:15 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "4 17/07/2013 04:05 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "5 17/07/2013 14:10 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "6 18/07/2013 02:05 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "7 18/07/2013 03:30 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "8 18/07/2013 03:40 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "9 18/07/2013 07:45 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "\n", " number status idr rnd \n", "0 14029 OPEN 25249 58 \n", "1 14029 OPEN 108821 76 \n", "2 14029 OPEN 337415 17 \n", "3 14029 OPEN 343560 60 \n", "4 14029 OPEN 547574 20 \n", "5 14029 OPEN 696283 10 \n", "6 14029 OPEN 872030 89 \n", "7 14029 OPEN 892923 8 \n", "8 14029 OPEN 895381 42 \n", "9 14029 OPEN 955602 15 "]}, "execution_count": 13, "metadata": {}, "output_type": "execute_result"}], "source": ["%%SQL --df=df\n", "SELECT * FROM (\n", " SELECT *,arandomfunction() AS rnd FROM velib)\n", " WHERE rnd==1"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We look at the head:"]}, {"cell_type": "code", "execution_count": 13, "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", "
addressavailable_bike_standsavailable_bikesbankingbike_standsbonuscontract_namelast_updatelatlngnamenumberstatusidrrnd
0112 RUE VERCINGETORIX - 75014 PARIS6610670Paris15/07/2013 16:4048,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN2524958
1112 RUE VERCINGETORIX - 75014 PARIS53140670Paris15/07/2013 22:2048,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN10882176
2112 RUE VERCINGETORIX - 75014 PARIS6160670Paris16/07/2013 13:5048,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN33741517
3112 RUE VERCINGETORIX - 75014 PARIS6160670Paris16/07/2013 14:1548,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN34356060
4112 RUE VERCINGETORIX - 75014 PARIS6160670Paris17/07/2013 04:0548,834259252,31339164714029 - GERGOVIE VERCINGETORIX14029OPEN54757420
\n", "
"], "text/plain": [" address available_bike_stands \\\n", "0 112 RUE VERCINGETORIX - 75014 PARIS 66 \n", "1 112 RUE VERCINGETORIX - 75014 PARIS 53 \n", "2 112 RUE VERCINGETORIX - 75014 PARIS 61 \n", "3 112 RUE VERCINGETORIX - 75014 PARIS 61 \n", "4 112 RUE VERCINGETORIX - 75014 PARIS 61 \n", "\n", " available_bikes banking bike_stands bonus contract_name \\\n", "0 1 0 67 0 Paris \n", "1 14 0 67 0 Paris \n", "2 6 0 67 0 Paris \n", "3 6 0 67 0 Paris \n", "4 6 0 67 0 Paris \n", "\n", " last_update lat lng name \\\n", "0 15/07/2013 16:40 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "1 15/07/2013 22:20 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "2 16/07/2013 13:50 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "3 16/07/2013 14:15 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "4 17/07/2013 04:05 48,83425925 2,313391647 14029 - GERGOVIE VERCINGETORIX \n", "\n", " number status idr rnd \n", "0 14029 OPEN 25249 58 \n", "1 14029 OPEN 108821 76 \n", "2 14029 OPEN 337415 17 \n", "3 14029 OPEN 343560 60 \n", "4 14029 OPEN 547574 20 "]}, "execution_count": 14, "metadata": {}, "output_type": "execute_result"}], "source": ["df.head()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you into column ``rnd``, you can see that it does not contain the value if was filtered on. It is probably because the python function is evaluated twice. We add this new dataframe to the database:"]}, {"cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [{"data": {"text/plain": ["86"]}, "execution_count": 15, "metadata": {}, "output_type": "execute_result"}], "source": ["%SQL_import_df -t sample df"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We check it is part the list of tables:"]}, {"cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [{"data": {"text/plain": ["['sample', 'velib']"]}, "execution_count": 16, "metadata": {}, "output_type": "execute_result"}], "source": ["%SQL_tables"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We do some more queries:"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["unable to execute a SQL request (1)(file notebook_example.db3)\n", "SELECT insample, COUNT(*) AS nb FROM (\n", " SELECT velib.*, sample.idr AS insample \n", " FROM velib OUTER JOIN sample\n", " ON velib.idr == sample.idr\n", ")\n", "RIGHT and FULL OUTER JOINs are not currently supported\n", "'SELECT insample, COUNT(*) AS nb FROM (\n", " SELECT velib.*, sample.idr AS insample \n", " FROM velib OUTER JOIN sample\n", " ON velib.idr == sample.idr\n", ")'\n"]}], "source": ["%%SQL\n", "\n", "SELECT insample, COUNT(*) AS nb FROM (\n", " SELECT velib.*, sample.idr AS insample \n", " FROM velib OUTER JOIN sample\n", " ON velib.idr == sample.idr\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We fix it:"]}, {"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", "
insamplenb
009375
1186
\n", "
"], "text/plain": [" insample nb\n", "0 0 9375\n", "1 1 86"]}, "execution_count": 18, "metadata": {}, "output_type": "execute_result"}], "source": ["%%SQL\n", "\n", "SELECT insample, COUNT(*) AS nb FROM (\n", " SELECT velib.idr, sample.idr is not null insample\n", " FROM velib LEFT OUTER JOIN sample\n", " ON velib.idr == sample.idr\n", ") GROUP BY insample"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Autocompletion also works when the prefix is ``DB.CC.``:"]}, {"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", "
available_bike_standsCOUNT(*)
0460
157
267
371
481
594
61037
71162
81253
91327
\n", "
"], "text/plain": [" available_bike_stands COUNT(*)\n", "0 4 60\n", "1 5 7\n", "2 6 7\n", "3 7 1\n", "4 8 1\n", "5 9 4\n", "6 10 37\n", "7 11 62\n", "8 12 53\n", "9 13 27"]}, "execution_count": 19, "metadata": {}, "output_type": "execute_result"}], "source": ["%%SQL --df=dfo\n", "SELECT DB.CC.velib.available_bike_stands, COUNT(*) \n", "FROM DB.CC.velib \n", "GROUP BY DB.CC.velib.available_bike_stands"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [{"data": {"text/plain": ["(64, 2)"]}, "execution_count": 20, "metadata": {}, "output_type": "execute_result"}], "source": ["dfo.shape"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The autocompletion looks like:"]}, {"cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [{"data": {"image/png": "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\nH9uhN/Bmxxx1OSNto1P1VYGsSe//zTELbz4VaErvIj66HqrTUE47Hr5P5fPHn/jEqlWrVq/+6o9P\n2K++XP+ff/nTz33ui1/84pe+9CV6Z/qH58+8+eabJ09u/ec/+5ufvXz0tddmfvyXf//UC7MzP/nr\nb/90hu5R2ncQv376B1ObZ8xxQFk1P3j619Y0szmc+G7uIFgls4X1qjRolqnNT3tbfRyNd4kcigP1\n5czkE0l2QkggnZS52Svy3p0yiUaCpYdqZP/+/bQ3JzU/dOjQa6+9ZgT95MmTVFlnzpwxm3Tz4MU8\nTE803RTyEgNNDzjVTETdSKsVZ3XCFNm5RT4e5WFsOx4mkXWSXJglmdKj4oaZfYCJ++57eIfeBex4\nZPUf/Mnj/6sev2z/1po1f7XdbtW3/e0ffuUr333+DMn68xse+ua/7z1x7NjWTX8+Nf3SkddmHnvk\nkcdn6CY9dOjgwd0//943n5g5GDPzxDeNUfV+7+e7ndEcKqMfo1yN2Q+KjnmE+CSQzELYOCF4VRw/\nK+9Xx4VsxYkku5SAcilO6o7JwRx2zQQsJ7o+DtHGnKT8yJEjpObHjh07ceIE7dCNoJ8/f35+fp5v\n0s2Dl+X9Aem9e/f+H1GLD5dBmSCgAAAAAElFTkSuQmCC\n", "text/plain": [""]}, "execution_count": 21, "metadata": {}, "output_type": "execute_result"}], "source": ["from pyquickhelper.helpgen import NbImage\n", "NbImage(\"dbcc.png\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We finally draw a graph:"]}, {"cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [{"data": {"text/plain": [""]}, "execution_count": 22, "metadata": {}, "output_type": "execute_result"}, {"data": {"image/png": "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\nqlKlSoFtPyiSk5NVvnz5UmsvJSWlUK+92aWlpenjjz/WqlWrtG7dOm3cuFHR0dFKSEhQ3bp15e7u\nXuRlzp49W127dnXYXkREhKKjo3X9+nXVqlXLNi0sLEytW7e2m7ty5Yo++OADHThwQPXr19dnn32m\nVatWKS4uTo0aNVKFChXs5lJTU5WVlWX7l5mZqSlTpqh79+7KyspyuH4HDx5UtWrVbH0OCwvTunXr\ndPToUTVq1MjhtrZ27VrVrl1bHh4eOnHihGbMmKHt27dr06ZNqlOnjsPPskmTJunq1avy9/eXl5eX\n3XnsOXHihBYtWqRDhw6pbt26mjt3rlatWqV9+/apbt268vPzs5vLyMjQp59+qlWrVunDDz/Upk2b\ntG/fPrm6uqp27doO28vJydG2bdv00UcfaePGjdq6datiY2OVnp6uhx9+WC4uRT/IZ/ny5Q7v952b\nm6uoqCjFxMTIzc0tz4+Gn376qZo0aWI3l5mZqS+++ELHjh1TnTp19N///lfr1q3TqVOn1KBBA7m5\nFf5OcWPGjNFTTz3lcPrp06fl6+sr6cbRNRs2bNDnn3+uM2fO5NvWli1bbPuQ8+fP66233tLq1au1\nb98+1a9f3+GXlLffflvZ2dmqWrVqkdbjwoULev/993XixAnVq1dPYWFh+ve//624uDjVrVtXFStW\ntJvLzc3Vjh07bK/5tm3bFBcXp0qVKuW7D2Jbse9+3l6Ku61I7IvMsC9ylv0Q20rZbytS8beXgpTq\nfVyLa86cOdq8ebPWr1+vQYMGqXbt2nJ3d3e4o7kpJyfH9v9t27Zp+vTp8vb2Vt++fTVt2jT169fP\nbs4wDLm6ukqSTp48aRvxbdSokSZMmOCwvapVqyokJESHDx/Wnj179PHHHysoKEidO3dWhw4dHG6E\nhmEoOztbGRkZyszMVFpamry8vHT9+vU863C7bdu26a233pKLi4v69OmjOXPmaObMmXr88cf1r3/9\nS//617/s5tLS0rRhwwbFxMQoOTlZFotFPj4+atu2rfr16+fwC0p+Zs+eralTpzpsLzIyUgkJCWrV\nqpW6dOlimxYWFqahQ4fazV25ckURERGyWCz6/e9/ry+//FLffvutqlevrpdeesnhh11qamqevw3D\n0NSpU22vo6M30MGDB9WyZUtbn1evXq0TJ06oZs2aevHFF21fJm63du1a9e3bV97e3jpx4oTmz58v\ni8WinJwcvfbaaw6300mTJql9+/bq3Lmz7cOkME6cOKE1a9bIz89Pf/zjH/XOO+/o+PHjCgwM1PDh\nw1WnTh2QcErYAAAY8ElEQVS7uYyMDH322We2EXo3NzdVq1ZNjz/+uHr06GE3M3/+fDVt2lQzZ860\nrf+VK1cUHR2t+fPn669//avd3MmTJx32/9SpUw6nLV26VA899JA6dOigHTt2aO/evRozZozKlSun\n+Ph4h7klS5aodevWyszM1KxZs9SlSxdNmTJFMTExWrFihSZOnGg398orr9xxhERiYqImTZoki8Xi\n8JSEf//737Zt5f3335efn58mTZqkb7/9Vu+++67D9vbv36/nn39ekrRmzRqNHTtW9erV07lz5xQa\nGqqQkBC7udTUVF27dk2zZs2Sr6+vOnfurE6dOsnf39/hcyLdeH8NHDhQ165d0/Tp0/Xiiy9q+vTp\nOnz4sMLCwvSPf/zDbi40NFTt27fXtGnT9M033ygjI0OdO3fWp59+qnPnzumPf/yj3dyiRYtUsWJF\nDRgwQFarVZKUkJCgnTt3atGiRRo3bpzD9bPHMAwdOHDA4fq9++67yszMVL169RQeHq4mTZroxRdf\nlCTt27dPv/vd7+zmlixZooCAAGVlZSkkJETVq1fXM888o9jYWK1YsUKjRo2ymxs8eLAsFoutb9KN\nwubm46tXr74js3TpUttnz4cffqiUlBT17dtX+/bt04oVKxweUbN161Y9+eSTkqTw8HD17t1b7du3\nV1xcnFasWKG///3vdnPx8fGyWCwKDw9Xs2bN1KVLF7Vu3brAomTp0qXq3Lmz0tLSNG3aNPXo0UPP\nPvusDh06pHfeeUd/+9vf7OaWLVumgIAA/d///Z/27t2rChUqqHHjxlq/fr3OnDnjsFBjW7lzW5Hu\n7+2luNuKxL7IDPsiZ9kPsa2U/bYiFX97KYhTFK43C7NHH31Uq1evlo+PT74F3U2GYSg1NVWGYcgw\nDHl7e0uSypcvbytM7alZs6Z27Nihnj176uGHH9aJEydUt25dnTt3Lt8Pc4vFIhcXF7Vo0UItWrRQ\ndna2Dh48qK+//loffPCBVq5caTfXs2dPjR07Vrm5uXruuec0b948ValSRfHx8Q5Hd2/KycmRi4uL\nrl+/royMDElSQEBAvs8Pb2rnflOX5k7g4sWLmjZtWp7HfH191a9fP+3YscNhH6dMmeKwYL927ZrD\n3IULF/SXv/xFktS+fXutX79eb7zxhsPn/qbk5GTbl56vvvrK9qPUU089pe3btzvMvfDCCzp06JAG\nDRpk+5X0z3/+s5YsWZJve7c6ceKE3nrrLUlSnz59tHPnTofz5ubmKicnR66ursrKylK9evUkSYGB\ngbp+/brDnJeXlwYPHqzBgwfr6NGj2r17tyZNmqQaNWqoc+fOtiNLbpeTk6NWrVpJuvEDS8eOHSVJ\nzZo10wcffOCwvUuXLtl+zOjTp4+mTJmiZ599ViNHjtT48eMdfmH46aeftHDhwjyPWa1WNWjQQGPG\njHHY3iuvvKLKlSvr1jNXLBaLDMNQcnKyw9zx48f19ttvS5KefPJJhYWF6e2339aYMWOU31kwv/76\nq8aPHy/DMDR8+HBNnz5dFoulwB8ne/ToobS0NL3wwgu2z86Ctpdb+3H48GHNmTNHbm5uaty4cb5t\n3foZfvXqVbVv316S1LRpU6WnpzvM+fj46PXXX1daWppiY2O1bds2LV++XG3atFHnzp0dniaTnp5u\nO7rnq6++Ut++fSVJvXr10pYtWxy2d/LkSY0cOVLSjR93p02bpt///vdq3LixJk6c6LAYYVux737e\nXoq7rUjsiwrjXu+LnGU/xLZSMDN/bymIUxSuN1mtVo0fP1779+93OHp5q7S0NE2ePFmGYchisSgp\nKUl+fn7KyMjId0f16quvKjw8XOvXr1elSpX017/+VVarVVarVX/6058c5m5fppubm9q2bau2bdsq\nMzPTYa5Pnz62AtXf31/du3fX4cOHFRwcbNtA7Hnsscc0ZcoU1atXTz/88IN++9vfSrqx08pvWJ43\ndcHM/KYuzZ1A5cqV9dlnn6l79+53/MiR37ncNWrU0PDhw/XQQw/dMW3EiBEOc9nZ2crNzbUdJti/\nf3/5+/vrb3/7m+2HGXtufe917949z7Tc3FyHub59+6pTp05avXq1rFarBg4caBslyU9ycrI2bdok\nwzCUnp5u+4y5vS+3e+KJJzRnzhz169dPLVq0UHh4uDp06KAjR47ke+jTrRo3bqzGjRvr5Zdf1qFD\nh7Rnzx6H20q5cuX0v//9T2lpabJYLNq3b5/at2+v77//Pt9DMT08PPTDDz+oUaNGio2NtX2euLi4\n5Lt+Xl5e+uabb9ShQwfb8nNzc7V37958j+SoWrWqZsyYYXebKmh7ucnV1VV/+tOfFBERoTfeeCPf\n7eUmi8WiVq1a2V47i8WS7+v/8ssv6+TJk1q4cKHatWunJ598ssDtJS0tTd9++63tyJqbP34W1FbH\njh21ZMkSPfvss2rXrp2++OILtW/fXkeOHMn3vXdzmZ6enurWrZu6deumlJQUffPNN4qMjHRYiFgs\nFp07d05paWnKysqy/WB7/vz5fN9Drq6uOn/+vKpVq6aTJ0/a1q9cuXL5Pi9sK/alpaVp3759ys3N\nve+2l+JuK9L9sS/K77PT2fZFZt4Psa3YV9rbyq3LLMr2UhCnKlxvat26tcNjxm/lqFCxWCz5/nLp\n6empP//5z0pLS9PFixeVm5srf39/h4eK3jR27FiH0wo63/HWUbaKFSvaipH8PP3002rWrJl++eUX\n9e3bV9WrV5ckeXt7a9asWQ5z98ObmmKkdHYCY8eOVWRkpGbOnGkbzfD19VWbNm0cHsonSQMGDHC4\nzJdeeslhrk2bNjpy5IiaN29ue6xHjx7y9fXVqlWrHObatm2rjIwMlS9fXs8995zt8fPnzyswMNBh\nTvp/P4jFxsbqzTffzPdHppsee+wx2yhG9+7dlZKSIm9vb125ciXf1/ypp55SrVq1tHXrVv3666/K\nycnR+fPn1a5dO/Xv399hzt57zsXFRS1btrQdJWDPsGHDtHbtWlksFk2bNk1bt27V0qVL5e/vn++P\ncEOHDtXy5ct1/vx51ahRw/b+vnr1qn7zm984zI0ZM0Zr167VypUrbcXHtWvX1LRp03w/H59++mml\npqba/fx55plnHOaCgoLyHOIv3dj2/P39FRYW5jBXt25d2/ZycwRIurG9FHQufFBQkKZPn64tW7Zo\n5syZ+f44JUlNmjTRd999J0mqX7++rly5Il9fX125ciXfi1v84Q9/UHR0tBYuXKgLFy7o+vXrioqK\nUrt27TR69GiHOXv9r1Spkp544gmH10uQbvzg989//lMuLi6aMGGCNmzYoDNnzigtLS3fbWXQoEGa\nNWuWypUrp5ycHNvrfPXqVbVp08Zh7ua2EhYWJi8vLxmGobS0tAd6W5Fu7AtiY2MlFX172bFjhym2\nl+HDh9vN3NxW3NzclJubaxtZL2hbke6PfZG9z/FbmX1fVJL7oXfeeUd+fn4OtxWp+PshthX7Svt7\ni73vXoXZXgriFFcVRslKTU1VZGSkYmNj73hT9+vXz+Fo7d69e1WrVi27G+PN4smeNWvWqHnz5nne\n1NKNc0pXrVql0NBQu7l169bpt7/97R071vPnz2vt2rV6/fXXC1zX2NhYbdiwQRcvXtSKFSvynTci\nIiLP37/5zW9sb+o1a9bke3XnuLi4PG/qgIAAtWvXTj179nR4WPqCBQvy/YLmyKlTp2w7gRdffFFb\nt27Vzp07bcVIw4YN7eZOnz6tZcuW5dkJBAYG6urVq/r666/19NNP28398ssvSkhIUIMGDfK8Frd/\nCbSXS0xMVP369Uskd+DAAdtI871qz8XFRefPn1etWrVKff3uVe7nn39WUlJSsXKJiYlFft1vnjNX\ntWpV/fLLLzp27Jhq1KhR4I+Nx48flyTVq1dPP//8sw4ePKjAwMBSz906qlZQ7ujRo4qLi1NQUFC+\n7d18Tu6mj2fPntXBgwdVvXr1e/ac3NrPs2fP6sCBA4V67Y4dOyYXF5cit3dTSkqKpBvnZuZXZDmy\nePHifD+f71Xu1h83C5KUlKTXX3893y+yBbVXVIsWLXJ4Du69aC8kJEQTJ07M9wdUwzBsX5jvpq2j\nR4/q+PHjqlWrVr53ibhdYe8uUda5o0eP6vvvv1e9evVKrb2iPp+l2VZR2rv1ziCZmZmKjIzUTz/9\nVOCdQW6/o8iGDRtKNVfYO5jcvn4RERH66aefVKdOnSLlivO8lMbzWRAKV+Rx89ze+ymXlZVlK0bM\n3E8z5jZv3qyvvvpK1atX1+nTpzVkyBC1a9dO0o2LS91+q6q7zX355ZfasmVLqeVKu59l0d7WrVsV\nGBhYKrmIiAgdPHhQOTk5at68uY4fP64mTZro8OHDatGihcNfZ2/PxcfHq2nTpqbPFWb9Suo5Ke3n\n8l730942dOTIkQJvc1fc2+OVdU4q3vqVdu5erl9x+yjdOFVpzpw5km5cmPKrr75Su3btdOjQIduP\n7gXloqKi9NVXX6l9+/amz23durXI67dt2zZt2bKlyO0V9vl0lnUbP3683nrrLbm6umr58uXy8PBQ\nx44ddfjwYZ0+fdp26ho5c+YKZAC3ePXVV8mRsxk/fryRnp5uGIZhXLhwwZg0aZLxxRdfGIZhGBMm\nTHC4PHIPbi4nJ8fIyMgwBg8ebFy7ds0wDMPIzMw0Xn/99Qcy5wx9LIvcxIkTjYULFxpHjhwx4uLi\njCNHjhjDhg0z4uLijLi4OIe5CRMmOEWutNfPGZ7P4rZ1M3vT5MmTjeTkZMMwDCM9Pd0YP348uVLI\nOUMfDcMwxo4da/v/xIkT80z7y1/+Qs7kuYI45TmuuDuOfuUwCrgqI7kHL2cYhu0w0SpVqmjmzJma\nO3euLl26lO95v+QezJyrq6tcXFzk4eGhqlWr2g4Fcnd3z/eQyvs55wx9LItccW9zFxIS4hS50l4/\nZ3g+i9uWVPy7RJAruZwz9FEq/p1ByJkjVxAK1wdQcnKypk2bdseVGw3D0PTp08mRs/Hx8dGpU6ds\nJ+6XL19ekydP1jvvvKMzZ844bIvcg5lzc3NTZmamPDw88twGKi0tLd/z3u7nnDP0sSxyxb3NHTnn\nzRW3Lan4d4kgV3I5Z+ijVPw7g5AzR65AhR2axf1j6dKlxtGjR+1OW7BgATlyNpcvXzaSkpLsTnO0\nLHIPbi4rK8vu48nJycbp06cfyJwz9LEscrf77rvvjLVr1xZ6fnLOnytuW7fKyMgwLly4QK4Mc2bt\n47Vr14yffvrJOHHihMP9GTnz5hzh4kwAAAAAAFNzfBwPAAAAAAAmQOEKAAAAADA1ClcAAAAAgKlR\nuAIA7muzZ89WdHS0JCk6Ojrfq2/f6uOPP1ZoaKjD6X/+85916NChYvfr4sWLGjhwoMMrq65fv17L\nli0r1LzOJC4uTq+++mpZdwMA4GS4HQ4A4L42derUsu5CsfTv379M2o2Ojta2bdv097//vUzaBwDA\nHkZcAQAAAACmxogrAMA0IiMjtW3bNiUnJ8tqteoPf/iDWrVqpWHDhumNN95QrVq1JElXr17ViBEj\ntHTpUrm6umrx4sWKj49Xbm6uGjZsqGHDhslqtUqSZs6cqa5du+qxxx67o73w8HDt27dPaWlpqlat\nmoYMGaLGjRvbpl+/fl3z58/XgQMH9NBDD2nEiBGqXbv2HcvJzc3Vxo0btW3bNl27dk2PPPKIhg8f\nLi8vrwLXeceOHYqIiJBhGOrTp4+eeeYZSTcOVT5//rxGjx59R2bv3r364IMPNGnSJNWqVUvHjh3T\n+++/r59//lmVK1fWkCFD1LRp03zbjY6O1ieffKKrV6+qUqVKeu6551SnTh2tWLFC2dnZGjRokFxd\nXfXee+9p//79+uijj3ThwgV5enqqZ8+eGjhwoKQbhzG/9tprGjlypNatW6esrCz17t3bNmKclZWl\nFStWKDY2Vr6+vurZs2eefkRGRurLL79Uenq6/Pz8NHToUDVr1qzA5w0A8GChcAUAmEbVqlU1a9Ys\n+fr6au/evVq0aJFCQ0PVvn177d6921a47tmzR02aNJGPj49SUlLUo0cPjRs3Trm5uXrnnXe0cuVK\nTZw4scD26tatq2effVaenp7avHmz5s2bpyVLlsjd3V2SFBsbqzFjxmjUqFHavHmz3nrrLS1cuFBu\nbnl3n1u2bFFMTIxmzpwpb29vhYeHKywsTGPHji2wD0eOHNHChQt18eJFzZo1S7Vr11bz5s0dzr9j\nxw6tX79e06dPV7Vq1ZSYmKiQkBC99tpratmypY4cOaK5c+dqwYIF8vb2truMjIwMhYeHa86cOQoM\nDFRSUpJSU1NVo0YNDRs27I5DhT08PPTaa6+pRo0aOnv2rN58803Vrl1b7du3t83zww8/aOHChTp3\n7pymTp2q9u3bq0aNGoqIiNCFCxe0aNEiZWRkaM6cObbMuXPn9NVXX2nOnDny9/fXxYsXlZubW+Bz\nBgB48HCoMADANB599FH5+/vLxcVFnTp1UrVq1XT8+HF16dJFe/bssc23e/dudenSRZJUqVIldezY\nUR4eHqpQoYL69++vo0ePFqq9bt26qVKlSnJ1dVXfvn2VnZ2tc+fO2aYHBQWpY8eOcnNzU58+fXT9\n+nXFx8ffsZz//Oc/eu6552S1WlWuXDkNGDBA3377baEupjRgwACVL19etWrVUs+ePbV7926H837x\nxRfauHGjZs6cqWrVqkmSdu3apVatWql169ZycXFR8+bNVbduXe3fvz/fdi0Wi86cOaOsrCz5+fmp\nZs2aDudt2rSpatWqJRcXFz388MPq3Lmzvv/++zvWw93dXbVr19bDDz+s06dPS5K++eYb9e/fX15e\nXgoICNBTTz1ly7i4uOj69ev6+eeflZ2drSpVqtjWCwCAWzHiCgAwjZ07d2rTpk26dOmSpBsjgykp\nKWrTpo0yMzMVHx8vHx8fnTp1yjbal5mZqdWrV+vgwYO6du2aJCk9PV25ublyccn/99mNGzdqx44d\nSkxMlMViUXp6ulJSUmzTbx5uLN0osqxWq5KSku5YzqVLl/T222/LYrHkmT85OVn+/v759uHWNgIC\nAnTmzBmH837++ef63e9+lydz+fJl7d27V999953tsZycnHwPFS5fvrzGjh2rzz//XMuWLVPDhg01\nePBgVa9e3e788fHx+vDDD3XmzBllZ2crOztbHTt2zDOPr6+v7f8eHh7KyMiQJCUlJd2xjjfdPDw7\nIiJCP//8s1q0aKHBgwcX+JwBAB48FK4AAFO4dOmSli9frhkzZqhBgwZycXHRhAkTZBiGXFxc9Oij\nj2r37t3y8fFR69atVaFCBUk3irlz585p9uzZ8vX11alTpzRx4kQZhpFve0ePHtXGjRs1Y8YM1ahR\nQy4uLnrppZfy5BISEmz/z83NVUJCgvz8/O5YltVq1YgRI9SoUaMir3dCQoKtYLx8+bLd5d80bdo0\n23reLBytVqu6du1a5FvMtGzZUi1btlRWVpY++ugjLV++XG+88YbdeUNDQ/Wb3/xGU6ZMkbu7u957\n7z1dvXq1UO34+voqISHBNqJ7+fLlPNO7dOmiLl26KC0tTe+++67Wrl2rUaNGFWldAAD3Pw4VBgCY\nQmZmpiwWi+28zB07dujs2bO26TcPF/76669thwlLN0Zl3d3d5enpqdTUVEVERBSqvfT0dLm6usrb\n21u5ubn65JNPlJaWlmeekydP2g753bx5s8qVK6f69evfsazHH39cH330kW2k+OrVq4qJiSlUPz79\n9FNlZmbq7Nmzio6OVqdOnRzOW7NmTU2dOlUrV65UbGysJKlr16767rvvdPDgQeXm5iorK0txcXF5\niu7bXblyRTExMcrIyJCbm5vKly9vGy329fVVYmKisrOz8zxXXl5ecnd31/Hjx/X1118Xat2kG4d/\nb9iwQampqUpISNCWLVts086dO6cjR47o+vXrcnd3l7u7e55RawAAbmLEFQBgCjVq1FCfPn00bdo0\nubi4qFu3bmrYsKFtev369eXh4aHExES1atXK9vjTTz+t0NBQvfLKK/L391efPn0KVTS2bNlSLVq0\n0JgxY+Th4aHevXvnOYxVktq2bas9e/ZoyZIlqlatml5//fU7Lsx0sw+S9OabbyopKUk+Pj569NFH\n1a5duwL70aRJE40ePVq5ubnq27evWrRoke/8tWvX1uTJkxUSEiJXV1e1atVKEydO1Jo1a7Rw4UK5\nuLioXr16GjZsmMNlGIahTZs2afHixbJYLKpdu7Zt/kceecR2kSYXFxetXLlSQ4cO1fvvv69Vq1ap\nSZMmevTRR22HZRdkwIABWrFihV577TX5+fmpZ8+e2rx5s6QbV21eu3atfvnlF7m6uqphw4YaPnx4\noZYLAHiwWIyCjqUCAAAAAKAMcagwAAAAAMDUOFQYAIB75L///a/efffdOx6vXLmy5s2bd8/bHzRo\nkN3Hp06dqsaNG9/z9gEAKCkcKgwAAAAAMDUOFQYAAAAAmBqFKwAAAADA1ChcAQAAAACmRuEKAAAA\nADA1ClcAAAAAgKn9f9MimOhVS5tVAAAAAElFTkSuQmCC\n", "text/plain": [""]}, "metadata": {}, "output_type": "display_data"}], "source": ["dfo.plot(x=\"available_bike_stands\", y=\"COUNT(*)\", kind=\"bar\", figsize=(16,4))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["And we finally close the connection:"]}, {"cell_type": "code", "execution_count": 22, "metadata": {"collapsed": true}, "outputs": [], "source": ["%SQL_close"]}, {"cell_type": "markdown", "metadata": {}, "source": ["**END**"]}, {"cell_type": "code", "execution_count": 23, "metadata": {"collapsed": true}, "outputs": [], "source": []}], "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.6.1"}}, "nbformat": 4, "nbformat_minor": 2}