"[sqlite-utils](https://sqlite-utils.datasette.io/en/stable/python-api.html) is a Python library (and [command-line tool](https://sqlite-utils.datasette.io/en/stable/cli.html) for quickly creating and manipulating SQLite database files.\n",
"\n",
"This tutorial will show you how to use the Python library to manipulate data.\n",
"\n",
"## Installation\n",
"\n",
"To install the library, run:\n",
"\n",
" pip install sqlite-utils\n",
"\n",
"You can run this in a Jupyter notebook cell by executing:\n",
"\n",
" %pip install sqlite-utils\n",
" \n",
"Or use `pip install -U sqlite-utils` to ensure you have upgraded to the most recent version."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "bddee0d2",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: sqlite_utils in /usr/local/Cellar/jupyterlab/3.0.16_1/libexec/lib/python3.9/site-packages (3.14)\n",
"Requirement already satisfied: click-default-group in /usr/local/lib/python3.9/site-packages (from sqlite_utils) (1.2.2)\n",
"Requirement already satisfied: sqlite-fts4 in /usr/local/lib/python3.9/site-packages (from sqlite_utils) (1.0.1)\n",
"Requirement already satisfied: click in /Users/simon/Library/Python/3.9/lib/python/site-packages (from sqlite_utils) (7.1.2)\n",
"Requirement already satisfied: tabulate in /usr/local/lib/python3.9/site-packages (from sqlite_utils) (0.8.7)\n",
"\u001b[33mWARNING: You are using pip version 21.1.1; however, version 21.2.2 is available.\n",
"You should consider upgrading via the '/usr/local/Cellar/jupyterlab/3.0.16_1/libexec/bin/python3.9 -m pip install --upgrade pip' command.\u001b[0m\n",
"Note: you may need to restart the kernel to use updated packages.\n"
]
}
],
"source": [
"%pip install -U sqlite_utils"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "050e85a8",
"metadata": {},
"outputs": [],
"source": [
"import sqlite_utils"
]
},
{
"cell_type": "markdown",
"id": "348bcbfc",
"metadata": {},
"source": [
"You can use the library with a database file on disk by running:\n",
"\n",
" db = sqlite_utils.Database(\"path/to/my/database.db\")\n",
"\n",
"In this tutorial we will use an in-memory database. This is a quick way to try out new things, though you should note that when you close the notebook the data store in the in-memory database will be lost."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "4b2aee7e",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<Database <sqlite3.Connection object at 0x139a16300>>"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"db = sqlite_utils.Database(memory=True)\n",
"db"
]
},
{
"cell_type": "markdown",
"id": "1598ab43",
"metadata": {},
"source": [
"## Creating a table\n",
"\n",
"We are going to create a new table in our database called `creatures` by passing in a Python list of dictionaries.\n",
"\n",
"`db[name_of_table]` will access a database table object with that name.\n",
"\n",
"Inserting data into that table will create it if it does not already exist."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "4a0ac420",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<Table creatures (name, species, age)>"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"db[\"creatures\"].insert_all([{\n",
" \"name\": \"Cleo\",\n",
" \"species\": \"dog\",\n",
" \"age\": 6\n",
"}, {\n",
" \"name\": \"Lila\",\n",
" \"species\": \"chicken\",\n",
" \"age\": 0.8,\n",
"}, {\n",
" \"name\": \"Bants\",\n",
" \"species\": \"chicken\",\n",
" \"age\": 0.8,\n",
"}])"
]
},
{
"cell_type": "markdown",
"id": "049d110b",
"metadata": {},
"source": [
"Let's grab a `table` reference to the new creatures table:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "8d84ad9c",
"metadata": {},
"outputs": [],
"source": [
"table = db[\"creatures\"]"
]
},
{
"cell_type": "markdown",
"id": "ffe45750",
"metadata": {},
"source": [
"`sqlite-utils` automatically creates a table schema that matches the keys and data types of the dictionaries that were passed to `.insert_all()`.\n",
"\n",
"We can see that schema using `table.schema`:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "136cee1e",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"CREATE TABLE [creatures] (\n",
" [name] TEXT,\n",
" [species] TEXT,\n",
" [age] FLOAT\n",
")\n"
]
}
],
"source": [
"print(table.schema)"
]
},
{
"cell_type": "markdown",
"id": "9e5c3ae9",
"metadata": {},
"source": [
"## Accessing data\n",
"\n",
"The `table.rows` property lets us loop through the rows in the table, returning each one as a Python dictionary:"
"for row in db.query(\"select name, species from creatures\"):\n",
" print(f'{row[\"name\"]} is a {row[\"species\"]}')"
]
},
{
"cell_type": "markdown",
"id": "b81c031c",
"metadata": {},
"source": [
"### SQL parameters\n",
"\n",
"You can run a parameterized query using `?` as placeholders and passing a list of variables. The variables you pass will be correctly quoted, protecting your code from SQL injection vulnerabilities."
"list(db.query(\"select * from creatures where species = :species\", {\"species\": \"chicken\"}))"
]
},
{
"cell_type": "markdown",
"id": "5e5179cc",
"metadata": {},
"source": [
"### Primary keys\n",
"\n",
"When we created this table we did not specify a primary key. SQLite automatically creates a primary key called `rowid` if no other primary key is defined.\n",
"\n",
"We can run `select rowid, * from creatures` to see this hidden primary key:"
"list(db.query(\"select * from creatures where id = ?\", [6]))"
]
},
{
"cell_type": "markdown",
"id": "58142b86",
"metadata": {},
"source": [
"## Extracting one of the columns into another table\n",
"\n",
"Our current table has a `species` column with a string in it - let's pull that out into a separate table.\n",
"\n",
"We can do that using the [table.extract() method](https://sqlite-utils.datasette.io/en/stable/python-api.html#extracting-columns-into-a-separate-table)."
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "6ab69111",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<Table creatures (id, name, species_id, age)>"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"table.extract(\"species\")"
]
},
{
"cell_type": "markdown",
"id": "dca327b2",
"metadata": {},
"source": [
"We now have a new table called `species`, which we can see using the `db.tables` method:"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "76e95b36",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[<Table species (id, species)>, <Table creatures (id, name, species_id, age)>]"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"db.tables"
]
},
{
"cell_type": "markdown",
"id": "5ea43bf5",
"metadata": {},
"source": [
"Our creatures table has been modified - instead of a `species` column it now has `species_id` which is a foreign key to the new table:"