Руководство по sqlite python

SQL и Python — обязательные инструменты для любого специалиста в сфере анализа данных. Это руководство — все, что вам нужно для первоначальной настройки и освоения основ работы с SQLite в Python. Оно включает следующие пункты:

  • Загрузка библиотеки
  • Создание и соединение с базой данных
  • Создание таблиц базы данных
  • Добавление данных
  • Запросы на получение данных
  • Удаление данных
  • И многое другое!

SQLite3 (часто говорят просто SQLite) — это часть стандартного пакета Python 3, поэтому ничего дополнительно устанавливать не придется.

Что будем создавать

В процессе этого руководства создадим базу данных в SQLite с помощью Python, несколько таблиц и настроим отношения:

Обзор базы данных, которую мы создадим.

Типы данных SQLite в Python

SQLite для Python предлагает меньше типов данных, чем есть в других реализациях SQL. С одной стороны, это накладывает ограничения, но, с другой стороны, в SQLite многое сделано проще. Вот основные типы:

  • NULL — значение NULL
  • INTEGER — целое число
  • REAL — число с плавающей точкой
  • TEXT — текст
  • BLOB — бинарное представление крупных объектов, хранящееся в точности с тем, как его ввели

К сожалению, других привычных для SQL типов данных в SQLite нет.

Первые шаги с SQLite в Python

Начнем руководство с загрузки библиотеки. Для этого нужно использовать следующую команду:

import sqlite3

Следующий шаг — создание базы данных.

Создание базы данных SQLite в Python

Есть несколько способов создания базы данных в Python с помощью SQLite. Для этого используется объект Connection, который и представляет собой базу. Он создается с помощью функции connect().

Создадим файл .db, поскольку это стандартный способ управления базой SQLite. Файл будет называться orders.db. За соединение будет отвечать переменная conn.

conn = sqlite3.connect('orders.db')

Эта строка создает объект connection, а также новый файл orders.db в рабочей директории. Если нужно использовать другую, ее нужно обозначить явно:

conn = sqlite3.connect(r'ПУТЬ-К-ПАПКИ/orders.db')

Если файл уже существует, то функция connect осуществит подключение к нему.

перед строкой с путем стоит символ «r». Это дает понять Python, что речь идет о «сырой» строке, где символы «/» не отвечают за экранирование.

Функция connect создает соединение с базой данных SQLite и возвращает объект, представляющий ее.

Резидентная база данных

Еще один способ создания баз данных с помощью SQLite в Python — создание их в памяти. Это отличный вариант для тестирования, ведь такие базы существуют только в оперативной памяти.

conn = sqlite3.connect(:memory:)

Однако в большинстве случаев (и в этом руководстве) будет использоваться описанный до этого способ.

Создание объекта cursor

После создания объекта соединения с базой данных нужно создать объект cursor. Он позволяет делать SQL-запросы к базе. Используем переменную cur для хранения объекта:

cur = conn.cursor()

Теперь выполнять запросы можно следующим образом:

cur.execute("ВАШ-SQL-ЗАПРОС-ЗДЕСЬ;")

Обратите внимание на то, что сами запросы должны быть помещены в кавычки — это важно. Это могут быть одинарные, двойные или тройные кавычки. Последние используются в случае особенно длинных запросов, которые часто пишутся на нескольких строках.

Создание таблиц в SQLite в Python

Пришло время создать первую таблицу в базе данных. С объектами соединения (conn) и cursor (cur) это можно сделать. Будем следовать этой схеме.

Быстрое напоминание о том, как выглядит наша база данных.

Начнем с таблицы users.

cur.execute("""CREATE TABLE IF NOT EXISTS users(
   userid INT PRIMARY KEY,
   fname TEXT,
   lname TEXT,
   gender TEXT);
""")
conn.commit()

В коде выше выполняются следующие операции:

  1. Функция execute отвечает за SQL-запрос
  2. SQL генерирует таблицу users
  3. IF NOT EXISTS поможет при попытке повторного подключения к базе данных. Запрос проверит, существует ли таблица. Если да — проверит, ничего ли не поменялось.
  4. Создаем первые четыре колонки: userid, fname, lname и gender. Userid — это основной ключ.
  5. Сохраняем изменения с помощью функции commit для объекта соединения.

Для создания второй таблицы просто повторим последовательность действий, используя следующие команды:

cur.execute("""CREATE TABLE IF NOT EXISTS orders(
   orderid INT PRIMARY KEY,
   date TEXT,
   userid TEXT,
   total TEXT);
""")
conn.commit()

После исполнения этих двух скриптов база данных будет включать две таблицы. Теперь можно добавлять данные.

Добавление данных с SQLite в Python

По аналогии с запросом для создания таблиц для добавления данных также нужно использовать объект cursor.

cur.execute("""INSERT INTO users(userid, fname, lname, gender) 
   VALUES('00001', 'Alex', 'Smith', 'male');""")
conn.commit()

В Python часто приходится иметь дело с переменными, в которых хранятся значения. Например, это может быть кортеж с информацией о пользователе.

user = ('00002', 'Lois', 'Lane', 'Female')

Если его нужно загрузить в базу данных, тогда подойдет следующий формат:

cur.execute("INSERT INTO users VALUES(?, ?, ?, ?);", user)
conn.commit()

В данном случае все значения заменены на знаки вопроса и добавлен параметр, содержащий значения, которые нужно добавить.

Важно заметить, что SQLite ожидает получить значения в формате кортежа. Однако в переменной может быть и список с набором кортежей. Таким образом можно добавить несколько пользователей:

more_users = [('00003', 'Peter', 'Parker', 'Male'), ('00004', 'Bruce', 'Wayne', 'male')]

Но нужно использовать функцию executemany вместо обычной execute:

cur.executemany("INSERT INTO users VALUES(?, ?, ?, ?);", more_users)
conn.commit()

Если применить execute, то функция подумает, то пользователь хочет передать в таблицу два объекта (два кортежа), а не два кортежа, каждый из которых содержит по 4 значения для каждого пользователя. Хотя в первую очередь вообще должна была возникнуть ошибка.

SQLite и предотвращение SQL-инъекций

Использование способа с вопросительными знаками (?, ?, …) также помогает противостоять SQL-инъекциям. Поэтому рекомендуется использовать его, а не упомянутый до этого.

Скрипты для загрузки данных

Следующие скрипты можно скопировать и вставить для добавления данных в обе таблицы:

customers = [
  ('00005', 'Stephanie', 'Stewart', 'female'), ('00006', 'Sincere', 'Sherman', 'female'), ('00007', 'Sidney', 'Horn', 'male'), 
  ('00008', 'Litzy', 'Yates', 'female'), ('00009', 'Jaxon', 'Mills', 'male'), ('00010', 'Paul', 'Richard', 'male'), 
  ('00011', 'Kamari', 'Holden', 'female'), ('00012', 'Gaige', 'Summers', 'female'), ('00013', 'Andrea', 'Snow', 'female'), 
  ('00014', 'Angelica', 'Barnes', 'female'), ('00015', 'Leah', 'Pitts', 'female'), ('00016', 'Dillan', 'Olsen', 'male'), 
  ('00017', 'Joe', 'Walsh', 'male'), ('00018', 'Reagan', 'Cooper', 'male'), ('00019', 'Aubree', 'Hogan', 'female'), 
  ('00020', 'Avery', 'Floyd', 'male'), ('00021', 'Elianna', 'Simmons', 'female'), ('00022', 'Rodney', 'Stout', 'male'), 
  ('00023', 'Elaine', 'Mcintosh', 'female'), ('00024', 'Myla', 'Mckenzie', 'female'), ('00025', 'Alijah', 'Horn', 'female'),
  ('00026', 'Rohan', 'Peterson', 'male'), ('00027', 'Irene', 'Walters', 'female'), ('00028', 'Lilia', 'Sellers', 'female'), 
  ('00029', 'Perla', 'Jefferson', 'female'), ('00030', 'Ashley', 'Klein', 'female')
]
orders = [
  ('00001', '2020-01-01', '00025', '178'), ('00002', '2020-01-03', '00025', '39'), ('00003', '2020-01-07', '00016', '153'), 
  ('00004', '2020-01-10', '00015', '110'), ('00005', '2020-01-11', '00024', '219'), ('00006', '2020-01-12', '00029', '37'), 
  ('00007', '2020-01-14', '00028', '227'), ('00008', '2020-01-18', '00010', '232'), ('00009', '2020-01-22', '00016', '236'), 
  ('00010', '2020-01-26', '00017', '116'), ('00011', '2020-01-28', '00028', '221'), ('00012', '2020-01-31', '00021', '238'), 
  ('00013', '2020-02-02', '00015', '177'), ('00014', '2020-02-05', '00025', '76'), ('00015', '2020-02-08', '00022', '245'), 
  ('00016', '2020-02-12', '00008', '180'), ('00017', '2020-02-14', '00020', '190'), ('00018', '2020-02-18', '00030', '166'),
  ('00019', '2020-02-22', '00002', '168'), ('00020', '2020-02-26', '00021', '174'), ('00021', '2020-02-29', '00017', '126'), 
  ('00022', '2020-03-02', '00019', '211'), ('00023', '2020-03-05', '00030', '144'), ('00024', '2020-03-09', '00012', '112'), 
  ('00025', '2020-03-10', '00006', '45'), ('00026', '2020-03-11', '00004', '200'), ('00027', '2020-03-14', '00015', '226'), 
  ('00028', '2020-03-17', '00030', '189'), ('00029', '2020-03-20', '00004', '152'), ('00030', '2020-03-22', '00026', '239'), 
  ('00031', '2020-03-23', '00012', '135'), ('00032', '2020-03-24', '00013', '211'), ('00033', '2020-03-27', '00030', '226'), 
  ('00034', '2020-03-28', '00007', '173'), ('00035', '2020-03-30', '00010', '144'), ('00036', '2020-04-01', '00017', '185'), 
  ('00037', '2020-04-03', '00009', '95'), ('00038', '2020-04-06', '00009', '138'), ('00039', '2020-04-10', '00025', '223'), 
  ('00040', '2020-04-12', '00019', '118'), ('00041', '2020-04-15', '00024', '132'), ('00042', '2020-04-18', '00008', '238'), 
  ('00043', '2020-04-21', '00003', '50'), ('00044', '2020-04-25', '00019', '98'), ('00045', '2020-04-26', '00017', '167'), 
  ('00046', '2020-04-28', '00009', '215'), ('00047', '2020-05-01', '00014', '142'), ('00048', '2020-05-05', '00022', '173'),
  ('00049', '2020-05-06', '00015', '80'), ('00050', '2020-05-07', '00017', '37'), ('00051', '2020-05-08', '00002', '36'), 
  ('00052', '2020-05-10', '00022', '65'), ('00053', '2020-05-14', '00019', '110'), ('00054', '2020-05-18', '00017', '36'), 
  ('00055', '2020-05-21', '00008', '163'), ('00056', '2020-05-24', '00024', '91'), ('00057', '2020-05-26', '00028', '154'), 
  ('00058', '2020-05-30', '00022', '130'), ('00059', '2020-05-31', '00017', '119'), ('00060', '2020-06-01', '00024', '137'), 
  ('00061', '2020-06-03', '00017', '206'), ('00062', '2020-06-04', '00013', '100'), ('00063', '2020-06-05', '00021', '187'), 
  ('00064', '2020-06-09', '00025', '170'), ('00065', '2020-06-11', '00011', '149'), ('00066', '2020-06-12', '00007', '195'), 
  ('00067', '2020-06-14', '00015', '30'), ('00068', '2020-06-16', '00002', '246'), ('00069', '2020-06-20', '00028', '163'),
  ('00070', '2020-06-22', '00005', '184'), ('00071', '2020-06-23', '00022', '68'), ('00072', '2020-06-27', '00013', '92'), 
  ('00073', '2020-06-30', '00022', '149'), ('00074', '2020-07-04', '00002', '65'), ('00075', '2020-07-05', '00017', '88'), 
  ('00076', '2020-07-09', '00007', '156'), ('00077', '2020-07-13', '00010', '26'), ('00078', '2020-07-16', '00008', '55'), 
  ('00079', '2020-07-20', '00019', '81'), ('00080', '2020-07-22', '00011', '78'), ('00081', '2020-07-23', '00026', '166'), 
  ('00082', '2020-07-27', '00014', '65'), ('00083', '2020-07-30', '00021', '205'), ('00084', '2020-08-01', '00026', '140'), 
  ('00085', '2020-08-05', '00006', '236'), ('00086', '2020-08-06', '00021', '208'), ('00087', '2020-08-07', '00021', '169'), 
  ('00088', '2020-08-08', '00004', '157'), ('00089', '2020-08-11', '00017', '71'), ('00090', '2020-08-13', '00025', '89'), 
  ('00091', '2020-08-16', '00014', '249'), ('00092', '2020-08-18', '00012', '59'), ('00093', '2020-08-19', '00013', '121'),
  ('00094', '2020-08-20', '00025', '179'), ('00095', '2020-08-22', '00017', '208'), ('00096', '2020-08-26', '00024', '217'), 
  ('00097', '2020-08-28', '00004', '206'), ('00098', '2020-08-30', '00017', '114'), ('00099', '2020-08-31', '00017', '169'), 
  ('00100', '2020-09-02', '00022', '226')
]

Используйте следующие запросы:

cur.executemany("INSERT INTO users VALUES(?, ?, ?, ?);", customers)
cur.executemany("INSERT INTO orders VALUES(?, ?, ?, ?);", orders)
conn.commit()

Получение данных с SQLite в Python

Следующий момент касательно SQLite в Python — выбор данных. Структура формирования запроса та же, но к ней будет добавлен еще один элемент.

Использование fetchone() в SQLite в Python

Начнем с использования функции fetchone(). Создадим переменную one_result для получения только одного результата:

cur.execute("SELECT * FROM users;")
one_result = cur.fetchone()
print(one_result)

Она вернет следующее:

[(1, 'Alex', 'Smith', 'male')]

Использование fetchmany() в SQLite в Python

Если же нужно получить много данных, то используется функция fetchmany(). Выполним другой скрипт для генерации 3 результатов:

cur.execute("SELECT * FROM users;")
three_results = cur.fetchmany(3)
print(three_results)

Он вернет следующее:

[(1, 'Alex', 'Smith', 'male'), (2, 'Lois', 'Lane', 'Female'), (3, 'Peter', 'Parker', 'Male')]

Использование fetchall() в SQLite в Python

Функцию fetchall() можно использовать для получения всех результатов. Вот что будет, если запустить скрипт:

cur.execute("SELECT * FROM users;")
all_results = cur.fetchall()
print(all_results)

Удаление данных в SQLite в Python

Теперь рассмотрим процесс удаления данных с SQLite в Python. Здесь та же структура. Предположим, нужно удалить любого пользователя с фамилией «Parker». Напишем следующее:

cur.execute("DELETE FROM users WHERE lname='Parker';")
conn.commit()

Если затем сделать следующей запрос:

cur.execute("select * from users where lname='Parker'")
print(cur.fetchall())

Будет выведен пустой список, подтверждающий, что запись удалена.

Объединение таблиц в SQLite в Python

Наконец, посмотрим, как использовать объединение данных для более сложных запросов. Предположим, нужно сгенерировать запрос, включающий имя и фамилию каждого покупателя заказа.

Для этого напишем следующее:

cur.execute("""SELECT *, users.fname, users.lname FROM orders
    LEFT JOIN users ON users.userid=orders.userid;""")
print(cur.fetchall())

Тот же подход работает с другими SQL-операциями.

Выводы

В этом материале вы узнали все, что требуется для работы с SQLite в Python: загрузка библиотеки, создание баз и таблиц, добавление, запрос и удаление данных.

Source code: Lib/sqlite3/


SQLite is a C library that provides a lightweight disk-based database that
doesn’t require a separate server process and allows accessing the database
using a nonstandard variant of the SQL query language. Some applications can use
SQLite for internal data storage. It’s also possible to prototype an
application using SQLite and then port the code to a larger database such as
PostgreSQL or Oracle.

The sqlite3 module was written by Gerhard Häring. It provides a SQL interface
compliant with the DB-API 2.0 specification described by PEP 249.

To use the module, you must first create a Connection object that
represents the database. Here the data will be stored in the
example.db file:

import sqlite3
conn = sqlite3.connect('example.db')

You can also supply the special name :memory: to create a database in RAM.

Once you have a Connection, you can create a Cursor object
and call its execute() method to perform SQL commands:

c = conn.cursor()

# Create table
c.execute('''CREATE TABLE stocks
             (date text, trans text, symbol text, qty real, price real)''')

# Insert a row of data
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)")

# Save (commit) the changes
conn.commit()

# We can also close the connection if we are done with it.
# Just be sure any changes have been committed or they will be lost.
conn.close()

The data you’ve saved is persistent and is available in subsequent sessions:

import sqlite3
conn = sqlite3.connect('example.db')
c = conn.cursor()

Usually your SQL operations will need to use values from Python variables. You
shouldn’t assemble your query using Python’s string operations because doing so
is insecure; it makes your program vulnerable to an SQL injection attack
(see https://xkcd.com/327/ for humorous example of what can go wrong).

Instead, use the DB-API’s parameter substitution. Put ? as a placeholder
wherever you want to use a value, and then provide a tuple of values as the
second argument to the cursor’s execute() method. (Other database
modules may use a different placeholder, such as %s or :1.) For
example:

# Never do this -- insecure!
symbol = 'RHAT'
c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)

# Do this instead
t = ('RHAT',)
c.execute('SELECT * FROM stocks WHERE symbol=?', t)
print(c.fetchone())

# Larger example that inserts many records at a time
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
             ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
             ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
            ]
c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)

To retrieve data after executing a SELECT statement, you can either treat the
cursor as an iterator, call the cursor’s fetchone() method to
retrieve a single matching row, or call fetchall() to get a list of the
matching rows.

This example uses the iterator form:

>>> for row in c.execute('SELECT * FROM stocks ORDER BY price'):
        print(row)

('2006-01-05', 'BUY', 'RHAT', 100, 35.14)
('2006-03-28', 'BUY', 'IBM', 1000, 45.0)
('2006-04-06', 'SELL', 'IBM', 500, 53.0)
('2006-04-05', 'BUY', 'MSFT', 1000, 72.0)

12.6.1. Module functions and constants¶

sqlite3.version

The version number of this module, as a string. This is not the version of
the SQLite library.

sqlite3.version_info

The version number of this module, as a tuple of integers. This is not the
version of the SQLite library.

sqlite3.sqlite_version

The version number of the run-time SQLite library, as a string.

sqlite3.sqlite_version_info

The version number of the run-time SQLite library, as a tuple of integers.

sqlite3.PARSE_DECLTYPES

This constant is meant to be used with the detect_types parameter of the
connect() function.

Setting it makes the sqlite3 module parse the declared type for each
column it returns. It will parse out the first word of the declared type,
i. e. for “integer primary key”, it will parse out “integer”, or for
“number(10)” it will parse out “number”. Then for that column, it will look
into the converters dictionary and use the converter function registered for
that type there.

sqlite3.PARSE_COLNAMES

This constant is meant to be used with the detect_types parameter of the
connect() function.

Setting this makes the SQLite interface parse the column name for each column it
returns. It will look for a string formed [mytype] in there, and then decide
that ‘mytype’ is the type of the column. It will try to find an entry of
‘mytype’ in the converters dictionary and then use the converter function found
there to return the value. The column name found in Cursor.description
is only the first word of the column name, i. e. if you use something like
'as "x [datetime]"' in your SQL, then we will parse out everything until the
first blank for the column name: the column name would simply be “x”.

sqlite3.connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri])

Opens a connection to the SQLite database file database. You can use
":memory:" to open a database connection to a database that resides in RAM
instead of on disk.

When a database is accessed by multiple connections, and one of the processes
modifies the database, the SQLite database is locked until that transaction is
committed. The timeout parameter specifies how long the connection should wait
for the lock to go away until raising an exception. The default for the timeout
parameter is 5.0 (five seconds).

For the isolation_level parameter, please see the
isolation_level property of Connection objects.

SQLite natively supports only the types TEXT, INTEGER, REAL, BLOB and NULL. If
you want to use other types you must add support for them yourself. The
detect_types parameter and the using custom converters registered with the
module-level register_converter() function allow you to easily do that.

detect_types defaults to 0 (i. e. off, no type detection), you can set it to
any combination of PARSE_DECLTYPES and PARSE_COLNAMES to turn
type detection on.

By default, check_same_thread is True and only the creating thread may
use the connection. If set False, the returned connection may be shared
across multiple threads. When using multiple threads with the same connection
writing operations should be serialized by the user to avoid data corruption.

By default, the sqlite3 module uses its Connection class for the
connect call. You can, however, subclass the Connection class and make
connect() use your class instead by providing your class for the factory
parameter.

Consult the section SQLite and Python types of this manual for details.

The sqlite3 module internally uses a statement cache to avoid SQL parsing
overhead. If you want to explicitly set the number of statements that are cached
for the connection, you can set the cached_statements parameter. The currently
implemented default is to cache 100 statements.

If uri is true, database is interpreted as a URI. This allows you
to specify options. For example, to open a database in read-only mode
you can use:

db = sqlite3.connect('file:path/to/database?mode=ro', uri=True)

More information about this feature, including a list of recognized options, can
be found in the SQLite URI documentation.

Changed in version 3.4: Added the uri parameter.

sqlite3.register_converter(typename, callable)

Registers a callable to convert a bytestring from the database into a custom
Python type. The callable will be invoked for all database values that are of
the type typename. Confer the parameter detect_types of the connect()
function for how the type detection works. Note that the case of typename and
the name of the type in your query must match!

sqlite3.register_adapter(type, callable)

Registers a callable to convert the custom Python type type into one of
SQLite’s supported types. The callable callable accepts as single parameter
the Python value, and must return a value of the following types: int,
float, str or bytes.

sqlite3.complete_statement(sql)

Returns True if the string sql contains one or more complete SQL
statements terminated by semicolons. It does not verify that the SQL is
syntactically correct, only that there are no unclosed string literals and the
statement is terminated by a semicolon.

This can be used to build a shell for SQLite, as in the following example:

# A minimal SQLite shell for experiments

import sqlite3

con = sqlite3.connect(":memory:")
con.isolation_level = None
cur = con.cursor()

buffer = ""

print("Enter your SQL commands to execute in sqlite3.")
print("Enter a blank line to exit.")

while True:
    line = input()
    if line == "":
        break
    buffer += line
    if sqlite3.complete_statement(buffer):
        try:
            buffer = buffer.strip()
            cur.execute(buffer)

            if buffer.lstrip().upper().startswith("SELECT"):
                print(cur.fetchall())
        except sqlite3.Error as e:
            print("An error occurred:", e.args[0])
        buffer = ""

con.close()
sqlite3.enable_callback_tracebacks(flag)

By default you will not get any tracebacks in user-defined functions,
aggregates, converters, authorizer callbacks etc. If you want to debug them,
you can call this function with flag set to True. Afterwards, you will
get tracebacks from callbacks on sys.stderr. Use False to
disable the feature again.

12.6.2. Connection Objects¶

class sqlite3.Connection

A SQLite database connection has the following attributes and methods:

isolation_level

Get or set the current isolation level. None for autocommit mode or
one of “DEFERRED”, “IMMEDIATE” or “EXCLUSIVE”. See section
Controlling Transactions for a more detailed explanation.

in_transaction

True if a transaction is active (there are uncommitted changes),
False otherwise. Read-only attribute.

New in version 3.2.

cursor(factory=Cursor)

The cursor method accepts a single optional parameter factory. If
supplied, this must be a callable returning an instance of Cursor
or its subclasses.

commit()

This method commits the current transaction. If you don’t call this method,
anything you did since the last call to commit() is not visible from
other database connections. If you wonder why you don’t see the data you’ve
written to the database, please check you didn’t forget to call this method.

rollback()

This method rolls back any changes to the database since the last call to
commit().

close()

This closes the database connection. Note that this does not automatically
call commit(). If you just close your database connection without
calling commit() first, your changes will be lost!

execute(sql[, parameters])

This is a nonstandard shortcut that creates a cursor object by calling
the cursor() method, calls the cursor’s
execute() method with the parameters given, and returns
the cursor.

executemany(sql[, parameters])

This is a nonstandard shortcut that creates a cursor object by
calling the cursor() method, calls the cursor’s
executemany() method with the parameters given, and
returns the cursor.

executescript(sql_script)

This is a nonstandard shortcut that creates a cursor object by
calling the cursor() method, calls the cursor’s
executescript() method with the given sql_script, and
returns the cursor.

create_function(name, num_params, func)

Creates a user-defined function that you can later use from within SQL
statements under the function name name. num_params is the number of
parameters the function accepts (if num_params is -1, the function may
take any number of arguments), and func is a Python callable that is
called as the SQL function.

The function can return any of the types supported by SQLite: bytes, str, int,
float and None.

Example:

import sqlite3
import hashlib

def md5sum(t):
    return hashlib.md5(t).hexdigest()

con = sqlite3.connect(":memory:")
con.create_function("md5", 1, md5sum)
cur = con.cursor()
cur.execute("select md5(?)", (b"foo",))
print(cur.fetchone()[0])
create_aggregate(name, num_params, aggregate_class)

Creates a user-defined aggregate function.

The aggregate class must implement a step method, which accepts the number
of parameters num_params (if num_params is -1, the function may take
any number of arguments), and a finalize method which will return the
final result of the aggregate.

The finalize method can return any of the types supported by SQLite:
bytes, str, int, float and None.

Example:

import sqlite3

class MySum:
    def __init__(self):
        self.count = 0

    def step(self, value):
        self.count += value

    def finalize(self):
        return self.count

con = sqlite3.connect(":memory:")
con.create_aggregate("mysum", 1, MySum)
cur = con.cursor()
cur.execute("create table test(i)")
cur.execute("insert into test(i) values (1)")
cur.execute("insert into test(i) values (2)")
cur.execute("select mysum(i) from test")
print(cur.fetchone()[0])
create_collation(name, callable)

Creates a collation with the specified name and callable. The callable will
be passed two string arguments. It should return -1 if the first is ordered
lower than the second, 0 if they are ordered equal and 1 if the first is ordered
higher than the second. Note that this controls sorting (ORDER BY in SQL) so
your comparisons don’t affect other SQL operations.

Note that the callable will get its parameters as Python bytestrings, which will
normally be encoded in UTF-8.

The following example shows a custom collation that sorts “the wrong way”:

import sqlite3

def collate_reverse(string1, string2):
    if string1 == string2:
        return 0
    elif string1 < string2:
        return 1
    else:
        return -1

con = sqlite3.connect(":memory:")
con.create_collation("reverse", collate_reverse)

cur = con.cursor()
cur.execute("create table test(x)")
cur.executemany("insert into test(x) values (?)", [("a",), ("b",)])
cur.execute("select x from test order by x collate reverse")
for row in cur:
    print(row)
con.close()

To remove a collation, call create_collation with None as callable:

con.create_collation("reverse", None)
interrupt()

You can call this method from a different thread to abort any queries that might
be executing on the connection. The query will then abort and the caller will
get an exception.

This routine registers a callback. The callback is invoked for each attempt to
access a column of a table in the database. The callback should return
SQLITE_OK if access is allowed, SQLITE_DENY if the entire SQL
statement should be aborted with an error and SQLITE_IGNORE if the
column should be treated as a NULL value. These constants are available in the
sqlite3 module.

The first argument to the callback signifies what kind of operation is to be
authorized. The second and third argument will be arguments or None
depending on the first argument. The 4th argument is the name of the database
(“main”, “temp”, etc.) if applicable. The 5th argument is the name of the
inner-most trigger or view that is responsible for the access attempt or
None if this access attempt is directly from input SQL code.

Please consult the SQLite documentation about the possible values for the first
argument and the meaning of the second and third argument depending on the first
one. All necessary constants are available in the sqlite3 module.

set_progress_handler(handler, n)

This routine registers a callback. The callback is invoked for every n
instructions of the SQLite virtual machine. This is useful if you want to
get called from SQLite during long-running operations, for example to update
a GUI.

If you want to clear any previously installed progress handler, call the
method with None for handler.

set_trace_callback(trace_callback)

Registers trace_callback to be called for each SQL statement that is
actually executed by the SQLite backend.

The only argument passed to the callback is the statement (as string) that
is being executed. The return value of the callback is ignored. Note that
the backend does not only run statements passed to the Cursor.execute()
methods. Other sources include the transaction management of the Python
module and the execution of triggers defined in the current database.

Passing None as trace_callback will disable the trace callback.

New in version 3.3.

enable_load_extension(enabled)

This routine allows/disallows the SQLite engine to load SQLite extensions
from shared libraries. SQLite extensions can define new functions,
aggregates or whole new virtual table implementations. One well-known
extension is the fulltext-search extension distributed with SQLite.

Loadable extensions are disabled by default. See [1].

New in version 3.2.

import sqlite3

con = sqlite3.connect(":memory:")

# enable extension loading
con.enable_load_extension(True)

# Load the fulltext search extension
con.execute("select load_extension('./fts3.so')")

# alternatively you can load the extension using an API call:
# con.load_extension("./fts3.so")

# disable extension laoding again
con.enable_load_extension(False)

# example from SQLite wiki
con.execute("create virtual table recipe using fts3(name, ingredients)")
con.executescript("""
    insert into recipe (name, ingredients) values ('broccoli stew', 'broccoli peppers cheese tomatoes');
    insert into recipe (name, ingredients) values ('pumpkin stew', 'pumpkin onions garlic celery');
    insert into recipe (name, ingredients) values ('broccoli pie', 'broccoli cheese onions flour');
    insert into recipe (name, ingredients) values ('pumpkin pie', 'pumpkin sugar flour butter');
    """)
for row in con.execute("select rowid, name, ingredients from recipe where name match 'pie'"):
    print(row)
load_extension(path)

This routine loads a SQLite extension from a shared library. You have to
enable extension loading with enable_load_extension() before you can
use this routine.

Loadable extensions are disabled by default. See [1].

New in version 3.2.

row_factory

You can change this attribute to a callable that accepts the cursor and the
original row as a tuple and will return the real result row. This way, you can
implement more advanced ways of returning results, such as returning an object
that can also access columns by name.

Example:

import sqlite3

def dict_factory(cursor, row):
    d = {}
    for idx, col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d

con = sqlite3.connect(":memory:")
con.row_factory = dict_factory
cur = con.cursor()
cur.execute("select 1 as a")
print(cur.fetchone()["a"])

If returning a tuple doesn’t suffice and you want name-based access to
columns, you should consider setting row_factory to the
highly-optimized sqlite3.Row type. Row provides both
index-based and case-insensitive name-based access to columns with almost no
memory overhead. It will probably be better than your own custom
dictionary-based approach or even a db_row based solution.

text_factory

Using this attribute you can control what objects are returned for the TEXT
data type. By default, this attribute is set to str and the
sqlite3 module will return Unicode objects for TEXT. If you want to
return bytestrings instead, you can set it to bytes.

You can also set it to any other callable that accepts a single bytestring
parameter and returns the resulting object.

See the following example code for illustration:

import sqlite3

con = sqlite3.connect(":memory:")
cur = con.cursor()

AUSTRIA = "xd6sterreich"

# by default, rows are returned as Unicode
cur.execute("select ?", (AUSTRIA,))
row = cur.fetchone()
assert row[0] == AUSTRIA

# but we can make sqlite3 always return bytestrings ...
con.text_factory = bytes
cur.execute("select ?", (AUSTRIA,))
row = cur.fetchone()
assert type(row[0]) is bytes
# the bytestrings will be encoded in UTF-8, unless you stored garbage in the
# database ...
assert row[0] == AUSTRIA.encode("utf-8")

# we can also implement a custom text_factory ...
# here we implement one that appends "foo" to all strings
con.text_factory = lambda x: x.decode("utf-8") + "foo"
cur.execute("select ?", ("bar",))
row = cur.fetchone()
assert row[0] == "barfoo"
total_changes

Returns the total number of database rows that have been modified, inserted, or
deleted since the database connection was opened.

iterdump()

Returns an iterator to dump the database in an SQL text format. Useful when
saving an in-memory database for later restoration. This function provides
the same capabilities as the .dump command in the sqlite3
shell.

Example:

# Convert file existing_db.db to SQL dump file dump.sql
import sqlite3

con = sqlite3.connect('existing_db.db')
with open('dump.sql', 'w') as f:
    for line in con.iterdump():
        f.write('%sn' % line)

12.6.3. Cursor Objects¶

class sqlite3.Cursor

A Cursor instance has the following attributes and methods.

execute(sql[, parameters])

Executes an SQL statement. The SQL statement may be parameterized (i. e.
placeholders instead of SQL literals). The sqlite3 module supports two
kinds of placeholders: question marks (qmark style) and named placeholders
(named style).

Here’s an example of both styles:

import sqlite3

con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.execute("create table people (name_last, age)")

who = "Yeltsin"
age = 72

# This is the qmark style:
cur.execute("insert into people values (?, ?)", (who, age))

# And this is the named style:
cur.execute("select * from people where name_last=:who and age=:age", {"who": who, "age": age})

print(cur.fetchone())

execute() will only execute a single SQL statement. If you try to execute
more than one statement with it, it will raise a Warning. Use
executescript() if you want to execute multiple SQL statements with one
call.

executemany(sql, seq_of_parameters)

Executes an SQL command against all parameter sequences or mappings found in
the sequence seq_of_parameters. The sqlite3 module also allows
using an iterator yielding parameters instead of a sequence.

import sqlite3

class IterChars:
    def __init__(self):
        self.count = ord('a')

    def __iter__(self):
        return self

    def __next__(self):
        if self.count > ord('z'):
            raise StopIteration
        self.count += 1
        return (chr(self.count - 1),) # this is a 1-tuple

con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.execute("create table characters(c)")

theIter = IterChars()
cur.executemany("insert into characters(c) values (?)", theIter)

cur.execute("select c from characters")
print(cur.fetchall())

Here’s a shorter example using a generator:

import sqlite3
import string

def char_generator():
    for c in string.ascii_lowercase:
        yield (c,)

con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.execute("create table characters(c)")

cur.executemany("insert into characters(c) values (?)", char_generator())

cur.execute("select c from characters")
print(cur.fetchall())
executescript(sql_script)

This is a nonstandard convenience method for executing multiple SQL statements
at once. It issues a COMMIT statement first, then executes the SQL script it
gets as a parameter.

sql_script can be an instance of str.

Example:

import sqlite3

con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.executescript("""
    create table person(
        firstname,
        lastname,
        age
    );

    create table book(
        title,
        author,
        published
    );

    insert into book(title, author, published)
    values (
        'Dirk Gently''s Holistic Detective Agency',
        'Douglas Adams',
        1987
    );
    """)
fetchone()

Fetches the next row of a query result set, returning a single sequence,
or None when no more data is available.

fetchmany(size=cursor.arraysize)

Fetches the next set of rows of a query result, returning a list. An empty
list is returned when no more rows are available.

The number of rows to fetch per call is specified by the size parameter.
If it is not given, the cursor’s arraysize determines the number of rows
to be fetched. The method should try to fetch as many rows as indicated by
the size parameter. If this is not possible due to the specified number of
rows not being available, fewer rows may be returned.

Note there are performance considerations involved with the size parameter.
For optimal performance, it is usually best to use the arraysize attribute.
If the size parameter is used, then it is best for it to retain the same
value from one fetchmany() call to the next.

fetchall()

Fetches all (remaining) rows of a query result, returning a list. Note that
the cursor’s arraysize attribute can affect the performance of this operation.
An empty list is returned when no rows are available.

close()

Close the cursor now (rather than whenever __del__ is called).

The cursor will be unusable from this point forward; a ProgrammingError
exception will be raised if any operation is attempted with the cursor.

rowcount

Although the Cursor class of the sqlite3 module implements this
attribute, the database engine’s own support for the determination of “rows
affected”/”rows selected” is quirky.

For executemany() statements, the number of modifications are summed up
into rowcount.

As required by the Python DB API Spec, the rowcount attribute “is -1 in
case no executeXX() has been performed on the cursor or the rowcount of the
last operation is not determinable by the interface”. This includes SELECT
statements because we cannot determine the number of rows a query produced
until all rows were fetched.

With SQLite versions before 3.6.5, rowcount is set to 0 if
you make a DELETE FROM table without any condition.

lastrowid

This read-only attribute provides the rowid of the last modified row. It is
only set if you issued an INSERT or a REPLACE statement using the
execute() method. For operations other than INSERT or
REPLACE or when executemany() is called, lastrowid is
set to None.

If the INSERT or REPLACE statement failed to insert the previous
successful rowid is returned.

Changed in version 3.6: Added support for the REPLACE statement.

arraysize

Read/write attribute that controls the number of rows returned by fetchmany().
The default value is 1 which means a single row would be fetched per call.

description

This read-only attribute provides the column names of the last query. To
remain compatible with the Python DB API, it returns a 7-tuple for each
column where the last six items of each tuple are None.

It is set for SELECT statements without any matching rows as well.

connection

This read-only attribute provides the SQLite database Connection
used by the Cursor object. A Cursor object created by
calling con.cursor() will have a
connection attribute that refers to con:

>>> con = sqlite3.connect(":memory:")
>>> cur = con.cursor()
>>> cur.connection == con
True

12.6.4. Row Objects¶

class sqlite3.Row

A Row instance serves as a highly optimized
row_factory for Connection objects.
It tries to mimic a tuple in most of its features.

It supports mapping access by column name and index, iteration,
representation, equality testing and len().

If two Row objects have exactly the same columns and their
members are equal, they compare equal.

keys()

This method returns a list of column names. Immediately after a query,
it is the first member of each tuple in Cursor.description.

Changed in version 3.5: Added support of slicing.

Let’s assume we initialize a table as in the example given above:

conn = sqlite3.connect(":memory:")
c = conn.cursor()
c.execute('''create table stocks
(date text, trans text, symbol text,
 qty real, price real)''')
c.execute("""insert into stocks
          values ('2006-01-05','BUY','RHAT',100,35.14)""")
conn.commit()
c.close()

Now we plug Row in:

>>> conn.row_factory = sqlite3.Row
>>> c = conn.cursor()
>>> c.execute('select * from stocks')
<sqlite3.Cursor object at 0x7f4e7dd8fa80>
>>> r = c.fetchone()
>>> type(r)
<class 'sqlite3.Row'>
>>> tuple(r)
('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14)
>>> len(r)
5
>>> r[2]
'RHAT'
>>> r.keys()
['date', 'trans', 'symbol', 'qty', 'price']
>>> r['qty']
100.0
>>> for member in r:
...     print(member)
...
2006-01-05
BUY
RHAT
100.0
35.14

12.6.5. Exceptions¶

exception sqlite3.Warning

A subclass of Exception.

exception sqlite3.Error

The base class of the other exceptions in this module. It is a subclass
of Exception.

exception sqlite3.DatabaseError

Exception raised for errors that are related to the database.

exception sqlite3.IntegrityError

Exception raised when the relational integrity of the database is affected,
e.g. a foreign key check fails. It is a subclass of DatabaseError.

exception sqlite3.ProgrammingError

Exception raised for programming errors, e.g. table not found or already
exists, syntax error in the SQL statement, wrong number of parameters
specified, etc. It is a subclass of DatabaseError.

12.6.6. SQLite and Python types¶

12.6.6.1. Introduction¶

SQLite natively supports the following types: NULL, INTEGER,
REAL, TEXT, BLOB.

The following Python types can thus be sent to SQLite without any problem:

Python type SQLite type
None NULL
int INTEGER
float REAL
str TEXT
bytes BLOB

This is how SQLite types are converted to Python types by default:

SQLite type Python type
NULL None
INTEGER int
REAL float
TEXT depends on text_factory,
str by default
BLOB bytes

The type system of the sqlite3 module is extensible in two ways: you can
store additional Python types in a SQLite database via object adaptation, and
you can let the sqlite3 module convert SQLite types to different Python
types via converters.

12.6.6.2. Using adapters to store additional Python types in SQLite databases¶

As described before, SQLite supports only a limited set of types natively. To
use other Python types with SQLite, you must adapt them to one of the
sqlite3 module’s supported types for SQLite: one of NoneType, int, float,
str, bytes.

There are two ways to enable the sqlite3 module to adapt a custom Python
type to one of the supported ones.

12.6.6.2.1. Letting your object adapt itself¶

This is a good approach if you write the class yourself. Let’s suppose you have
a class like this:

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

Now you want to store the point in a single SQLite column. First you’ll have to
choose one of the supported types first to be used for representing the point.
Let’s just use str and separate the coordinates using a semicolon. Then you need
to give your class a method __conform__(self, protocol) which must return
the converted value. The parameter protocol will be PrepareProtocol.

import sqlite3

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __conform__(self, protocol):
        if protocol is sqlite3.PrepareProtocol:
            return "%f;%f" % (self.x, self.y)

con = sqlite3.connect(":memory:")
cur = con.cursor()

p = Point(4.0, -3.2)
cur.execute("select ?", (p,))
print(cur.fetchone()[0])

12.6.6.2.2. Registering an adapter callable¶

The other possibility is to create a function that converts the type to the
string representation and register the function with register_adapter().

import sqlite3

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

def adapt_point(point):
    return "%f;%f" % (point.x, point.y)

sqlite3.register_adapter(Point, adapt_point)

con = sqlite3.connect(":memory:")
cur = con.cursor()

p = Point(4.0, -3.2)
cur.execute("select ?", (p,))
print(cur.fetchone()[0])

The sqlite3 module has two default adapters for Python’s built-in
datetime.date and datetime.datetime types. Now let’s suppose
we want to store datetime.datetime objects not in ISO representation,
but as a Unix timestamp.

import sqlite3
import datetime
import time

def adapt_datetime(ts):
    return time.mktime(ts.timetuple())

sqlite3.register_adapter(datetime.datetime, adapt_datetime)

con = sqlite3.connect(":memory:")
cur = con.cursor()

now = datetime.datetime.now()
cur.execute("select ?", (now,))
print(cur.fetchone()[0])

12.6.6.3. Converting SQLite values to custom Python types¶

Writing an adapter lets you send custom Python types to SQLite. But to make it
really useful we need to make the Python to SQLite to Python roundtrip work.

Enter converters.

Let’s go back to the Point class. We stored the x and y coordinates
separated via semicolons as strings in SQLite.

First, we’ll define a converter function that accepts the string as a parameter
and constructs a Point object from it.

Note

Converter functions always get called with a bytes object, no
matter under which data type you sent the value to SQLite.

def convert_point(s):
    x, y = map(float, s.split(b";"))
    return Point(x, y)

Now you need to make the sqlite3 module know that what you select from
the database is actually a point. There are two ways of doing this:

  • Implicitly via the declared type
  • Explicitly via the column name

Both ways are described in section Module functions and constants, in the entries
for the constants PARSE_DECLTYPES and PARSE_COLNAMES.

The following example illustrates both approaches.

import sqlite3

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __repr__(self):
        return "(%f;%f)" % (self.x, self.y)

def adapt_point(point):
    return ("%f;%f" % (point.x, point.y)).encode('ascii')

def convert_point(s):
    x, y = list(map(float, s.split(b";")))
    return Point(x, y)

# Register the adapter
sqlite3.register_adapter(Point, adapt_point)

# Register the converter
sqlite3.register_converter("point", convert_point)

p = Point(4.0, -3.2)

#########################
# 1) Using declared types
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)
cur = con.cursor()
cur.execute("create table test(p point)")

cur.execute("insert into test(p) values (?)", (p,))
cur.execute("select p from test")
print("with declared types:", cur.fetchone()[0])
cur.close()
con.close()

#######################
# 1) Using column names
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES)
cur = con.cursor()
cur.execute("create table test(p)")

cur.execute("insert into test(p) values (?)", (p,))
cur.execute('select p as "p [point]" from test')
print("with column names:", cur.fetchone()[0])
cur.close()
con.close()

12.6.6.4. Default adapters and converters¶

There are default adapters for the date and datetime types in the datetime
module. They will be sent as ISO dates/ISO timestamps to SQLite.

The default converters are registered under the name “date” for
datetime.date and under the name “timestamp” for
datetime.datetime.

This way, you can use date/timestamps from Python without any additional
fiddling in most cases. The format of the adapters is also compatible with the
experimental SQLite date/time functions.

The following example demonstrates this.

import sqlite3
import datetime

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
cur = con.cursor()
cur.execute("create table test(d date, ts timestamp)")

today = datetime.date.today()
now = datetime.datetime.now()

cur.execute("insert into test(d, ts) values (?, ?)", (today, now))
cur.execute("select d, ts from test")
row = cur.fetchone()
print(today, "=>", row[0], type(row[0]))
print(now, "=>", row[1], type(row[1]))

cur.execute('select current_date as "d [date]", current_timestamp as "ts [timestamp]"')
row = cur.fetchone()
print("current_date", row[0], type(row[0]))
print("current_timestamp", row[1], type(row[1]))

If a timestamp stored in SQLite has a fractional part longer than 6
numbers, its value will be truncated to microsecond precision by the
timestamp converter.

12.6.7. Controlling Transactions¶

By default, the sqlite3 module opens transactions implicitly before a
Data Modification Language (DML) statement (i.e.
INSERT/UPDATE/DELETE/REPLACE).

You can control which kind of BEGIN statements sqlite3 implicitly executes
(or none at all) via the isolation_level parameter to the connect()
call, or via the isolation_level property of connections.

If you want autocommit mode, then set isolation_level to None.

Otherwise leave it at its default, which will result in a plain “BEGIN”
statement, or set it to one of SQLite’s supported isolation levels: “DEFERRED”,
“IMMEDIATE” or “EXCLUSIVE”.

The current transaction state is exposed through the
Connection.in_transaction attribute of the connection object.

Changed in version 3.6: sqlite3 used to implicitly commit an open transaction before DDL
statements. This is no longer the case.

12.6.8. Using sqlite3 efficiently¶

12.6.8.1. Using shortcut methods¶

Using the nonstandard execute(), executemany() and
executescript() methods of the Connection object, your code can
be written more concisely because you don’t have to create the (often
superfluous) Cursor objects explicitly. Instead, the Cursor
objects are created implicitly and these shortcut methods return the cursor
objects. This way, you can execute a SELECT statement and iterate over it
directly using only a single call on the Connection object.

import sqlite3

persons = [
    ("Hugo", "Boss"),
    ("Calvin", "Klein")
    ]

con = sqlite3.connect(":memory:")

# Create the table
con.execute("create table person(firstname, lastname)")

# Fill the table
con.executemany("insert into person(firstname, lastname) values (?, ?)", persons)

# Print the table contents
for row in con.execute("select firstname, lastname from person"):
    print(row)

print("I just deleted", con.execute("delete from person").rowcount, "rows")

12.6.8.2. Accessing columns by name instead of by index¶

One useful feature of the sqlite3 module is the built-in
sqlite3.Row class designed to be used as a row factory.

Rows wrapped with this class can be accessed both by index (like tuples) and
case-insensitively by name:

import sqlite3

con = sqlite3.connect(":memory:")
con.row_factory = sqlite3.Row

cur = con.cursor()
cur.execute("select 'John' as name, 42 as age")
for row in cur:
    assert row[0] == row["name"]
    assert row["name"] == row["nAmE"]
    assert row[1] == row["age"]
    assert row[1] == row["AgE"]

12.6.8.3. Using the connection as a context manager¶

Connection objects can be used as context managers
that automatically commit or rollback transactions. In the event of an
exception, the transaction is rolled back; otherwise, the transaction is
committed:

import sqlite3

con = sqlite3.connect(":memory:")
con.execute("create table person (id integer primary key, firstname varchar unique)")

# Successful, con.commit() is called automatically afterwards
with con:
    con.execute("insert into person(firstname) values (?)", ("Joe",))

# con.rollback() is called after the with block finishes with an exception, the
# exception is still raised and must be caught
try:
    with con:
        con.execute("insert into person(firstname) values (?)", ("Joe",))
except sqlite3.IntegrityError:
    print("couldn't add Joe twice")

12.6.9. Common issues¶

12.6.9.1. Multithreading¶

Older SQLite versions had issues with sharing connections between threads.
That’s why the Python module disallows sharing connections and cursors between
threads. If you still try to do so, you will get an exception at runtime.

The only exception is calling the interrupt() method, which
only makes sense to call from a different thread.

Footnotes

[1] (1, 2) The sqlite3 module is not built with loadable extension support by
default, because some platforms (notably Mac OS X) have SQLite
libraries which are compiled without this feature. To get loadable
extension support, you must pass –enable-loadable-sqlite-extensions to
configure.

21 января 2022 г. | Python

SQLite – это C библиотека, реализующая легковесную дисковую базу данных (БД), не требующую
отдельного серверного процесса и позволяющую получить доступ к БД с использованием языка запросов SQL.
Некоторые приложения могут использовать SQLite для внутреннего хранения данных.
Также возможно создать прототип приложения с использованием SQLite, а затем перенести код в более многофункциональную БД, такую как PostgreSQL или Oracle.

Модуль sqlite3 реализует интерфейс SQL, соответствующий спецификации DB-API 2.0, описанной в PEP 249.

Создание соединения

Чтобы воспользоваться SQLite3 в Python необходимо импортировать
модуль sqlite3, а затем создать объект подключения к БД.

Объект подключения создается с помощью метода connect():

import sqlite3

con = sqlite3.connect('mydatabase.db')

Курсор SQLite3

Для выполнения операторов SQL, нужен объект курсора, создаваемый методом cursor().

Курсор SQLite3 – это метод объекта соединения. Для выполнения операторов SQLite3 сначала
устанавливается соединение, а затем создается объект курсора с использованием объекта
соединения следующим образом:

con = sqlite3.connect('mydatabase.db')

cursorObj = con.cursor()

Теперь можно использовать объект курсора для вызова метода execute() для выполнения
любых запросов SQL.

Создание базы данных

После создания соединения с SQLite, файл БД создается автоматически, при условии его отсутствия.
Данный файл создаётся на диске, но также можно создать базу данных в оперативной памяти,
используя параметр «:memory:» в методе connect. При этом база данных будет называется инмемори.

Рассмотрим приведенный ниже код, в котором создается БД с блоками try, except и finally для обработки любых исключений:

import sqlite3

from sqlite3 import Error

def sql_connection():

    try:

        con = sqlite3.connect(':memory:')

        print("Connection is established: Database is created in memory")

    except Error:

        print(Error)

    finally:

        con.close()

sql_connection()

Сначала импортируется модуль sqlite3, затем определяется функция с именем sql_connection.
Внутри функции определен блок try, где метод connect() возвращает объект соединения после установления соединения.

Затем определен блок исключений, который в случае каких-либо исключений печатает сообщение об ошибке.
Если ошибок нет, соединение будет установлено, тогда скрипт распечатает
текст «Connection is established: Database is created in memory».

Далее производится закрытие соединения в блоке finally. Закрытие соединения необязательно,
но это хорошая практика программирования, позволяющая освободить память от любых неиспользуемых ресурсов.

Создание таблицы

Чтобы создать таблицу в SQLite3, выполним запрос Create Table в методе execute(). Для этого выполним следующую последовательность шагов:

  1. Создание объекта подключения
  2. Объект Cursor создаётся с использованием объекта подключения
  3. Используя объект курсора, вызывается метод execute с SQL запросом create table в качестве параметра.

Давайте создадим таблицу Employees со следующими колонками:

employees (id, name, salary, department, position, hireDate)

Код будет таким:

import sqlite3

from sqlite3 import Error

def sql_connection():

    try:

        con = sqlite3.connect('mydatabase.db')

        return con

    except Error:

        print(Error)

def sql_table(con):

    cursorObj = con.cursor()

    cursorObj.execute("CREATE TABLE employees(id integer PRIMARY KEY, name text, salary real, department text, position text, hireDate text)")

    con.commit()

con = sql_connection()
sql_table(con)

В приведенном выше коде определено две функции: первая устанавливает соединение;
а вторая — используя объект курсора выполняет SQL оператор create table.

Метод commit() сохраняет все сделанные изменения. В конце скрипта производится вызов обеих функций.

Для проверки существования таблицы воспользуемся браузером БД для sqlite.

Вставка данных в таблицу

Чтобы вставить данные в таблицу воспользуемся оператором INSERT INTO. Рассмотрим следующую строку кода:

cursorObj.execute("INSERT INTO employees VALUES(1, 'John', 700, 'HR', 'Manager', '2017-01-04')")

Также можем передать значения / аргументы в оператор INSERT в методе execute (). Также можно использовать знак вопроса (?)
в качестве заполнителя для каждого значения. Синтаксис INSERT будет выглядеть следующим образом:

cursorObj.execute('''INSERT INTO employees(id, name, salary, department, position, hireDate) VALUES(?, ?, ?, ?, ?, ?)''', entities)

Где картеж entities содержат значения для заполнения одной строки в таблице:

entity = (2, 'Andrew', 800, 'IT', 'Tech', '2018-02-06')

Код выглядит следующим образом:

import sqlite3

con = sqlite3.connect('mydatabase.db')

def sql_insert(con, entities):

    cursorObj = con.cursor()

    cursorObj.execute('INSERT INTO employees(id, name, salary, department, position, hireDate) VALUES(?, ?, ?, ?, ?, ?)', entities)

    con.commit()

entities = (2, 'Andrew', 800, 'IT', 'Tech', '2018-02-06')

sql_insert(con, entities)

Обновление таблицы

Предположим, что нужно обновить имя сотрудника, чей идентификатор равен 2. Для обновления будем использовать
инструкцию UPDATE. Также воспользуемся предикатом WHERE в качестве условия для выбора нужного сотрудника.

Рассмотрим следующий код:

import sqlite3

con = sqlite3.connect('mydatabase.db')

def sql_update(con):

    cursorObj = con.cursor()

    cursorObj.execute('UPDATE employees SET name = "Rogers" where id = 2')

    con.commit()

sql_update(con)

Это изменит имя Andrew на Rogers.

Оператор SELECT

Оператор SELECT используется для выборки данных из одной или более таблиц. Если нужно выбрать все столбцы данных из таблицы,
можете использовать звёздочку (*). SQL синтаксис для этого будет следующим:

select * from table_name

В SQLite3 инструкция SELECT выполняется в методе execute объекта курсора. Например, выберем все стрики и столбцы таблицы employee:

cursorObj.execute('SELECT * FROM employees ')

Если нужно выбрать несколько столбцов из таблицы, укажем их, как показано ниже:

select column1, column2 from tables_name

Например,

cursorObj.execute('SELECT id, name FROM employees')

Оператор SELECT выбирает все данные из таблицы employees БД.

Выборка всех данных

Чтобы извлечь данные из БД выполним инструкцию SELECT, а затем воспользуемся методом fetchall()
объекта курсора для сохранения значений в переменной. При этом переменная будет являться списком,
где каждая строка из БД будет отдельным элементом списка. Далее будет выполняться перебор значений
переменной и печатать значений.

Код будет таким:

import sqlite3

con = sqlite3.connect('mydatabase.db')

def sql_fetch(con):

    cursorObj = con.cursor()

    cursorObj.execute('SELECT * FROM employees')

    rows = cursorObj.fetchall()

    for row in rows:

        print(row)

sql_fetch(con)

Также можно использовать fetchall() в одну строку:

[print(row) for row in cursorObj.fetchall()]

Если нужно извлечь конкретные данные из БД, воспользуйтесь предикатом WHERE. Например, выберем идентификаторы
и имена тех сотрудников, чья зарплата превышает 800. Для этого заполним нашу таблицу большим количеством строк, а затем выполним запрос.

Можете использовать оператор INSERT для заполнения данных или ввести их вручную в программе браузера БД.

Теперь, выберем имена и идентификаторы тех сотрудников, у кого зарплата больше 800:

import sqlite3

con = sqlite3.connect('mydatabase.db')

def sql_fetch(con):

    cursorObj = con.cursor()

    cursorObj.execute('SELECT id, name FROM employees WHERE salary > 800.0')

    rows = cursorObj.fetchall()

    for row in rows:

        print(row)

sql_fetch(con)

В приведенном выше операторе SELECT вместо звездочки (*) были указаны атрибуты id и name.

SQLite3 rowcount

Счётчик строк SQLite3 используется для возврата количества строк, которые были затронуты или выбраны последним выполненным запросом SQL.

Когда вызывается rowcount с оператором SELECT, будет возвращено -1, поскольку количество выбранных строк неизвестно
до тех пор, пока все они не будут выбраны. Рассмотрим пример:

print(cursorObj.execute('SELECT * FROM employees').rowcount)

Поэтому, чтобы получить количество строк, нужно получить все данные, а затем получить длину результата:

rows = cursorObj.fetchall()
print(len(rows))

Когда оператор DELETE используется без каких-либо условий (предложение where),
все строки в таблице будут удалены, а общее количество удаленных строк будет возвращено rowcount.

print(cursorObj.execute('DELETE FROM employees').rowcount)

Если ни одна строка не удалена, будет возвращено 0.

Список таблиц

Чтобы вывести список всех таблиц в базе данных SQLite3, нужно обратиться к таблице sqlite_master, а
затем использовать fetchall() для получения результатов из оператора SELECT.

Sqlite_master — это главная таблица в SQLite3, в которой хранятся все таблицы.

import sqlite3

con = sqlite3.connect('mydatabase.db')

def sql_fetch(con):

    cursorObj = con.cursor()

    cursorObj.execute('SELECT name from sqlite_master where type= "table"')

    print(cursorObj.fetchall())

sql_fetch(con)

Проверка существования таблицы

При создании таблицы необходимо убедиться, что таблица еще не существует. Аналогично, при удалении таблицы она должна существовать.

Чтобы проверить, если таблица еще не существует, используем «if not exists» с оператором CREATE TABLE следующим образом:

import sqlite3

con = sqlite3.connect('mydatabase.db')

def sql_fetch(con):

    cursorObj = con.cursor()

    cursorObj.execute('create table if not exists projects(id integer, name text)')

    con.commit()

sql_fetch(con)

Точно так же, чтобы проверить, существует ли таблица при удалении, мы используем «if not exists» с инструкцией DROP TABLE следующим образом:

cursorObj.execute('drop table if exists projects')

Также проверим, существует ли таблица, к которой нужно получить доступ, выполнив следующий запрос:

cursorObj.execute('SELECT name from sqlite_master WHERE type = "table" AND name = "employees"')

print(cursorObj.fetchall())

Если указанное имя таблицы не существует, будет возвращен пустой массив.

Удаление таблицы

Удаление таблицы выполняется с помощью оператора DROP. Синтаксис оператора DROP выглядит следующим образом:

drop table table_name

Чтобы удалить таблицу, таблица должна существовать в БД. Поэтому рекомендуется использовать «if exists» с
оператором DROP. Например, удалим таблицу employees:

import sqlite3

con = sqlite3.connect('mydatabase.db')

def sql_fetch(con):

    cursorObj = con.cursor()

    cursorObj.execute('DROP table if exists employees')

    con.commit()

sql_fetch(con)

Исключения SQLite3

Исключением являются ошибки времени выполнения скрипта. При программировании на Python все исключения
являются экземплярами класса производного от BaseException.

В SQLite3 у есть следующие основные исключения Python:

DatabaseError

Любая ошибка, связанная с базой данных, вызывает ошибку DatabaseError.

IntegrityError

IntegrityError является подклассом DatabaseError и возникает, когда возникает проблема целостности данных,
например, когда внешние данные не обновляются во всех таблицах, что приводит к несогласованности данных.

ProgrammingError

Исключение ProgrammingError возникает, когда есть синтаксические ошибки или таблица не найдена
или функция вызывается с неправильным количеством параметров / аргументов.

OperationalError

Это исключение возникает при сбое операций базы данных, например, при необычном отключении. Не по вине программиста.

NotSupportedError

При использовании некоторых методов, которые не определены или не поддерживаются базой данных, возникает
исключение NotSupportedError.

Массовая вставка строк в Sqlite

Для вставки нескольких строк одновременно использовать оператор executemany.

Рассмотрим следующий код:

import sqlite3

con = sqlite3.connect('mydatabase.db')

cursorObj = con.cursor()

cursorObj.execute('create table if not exists projects(id integer, name text)')

data = [(1, "Ridesharing"), (2, "Water Purifying"), (3, "Forensics"), (4, "Botany")]

cursorObj.executemany("INSERT INTO projects VALUES(?, ?)", data)

con.commit()

Здесь создали таблицу с двумя столбцами, тогда у «данных» есть четыре значения для каждого столбца.
Эта переменная передается методу executemany() вместе с запросом.

Обратите внимание, что использовался заполнитель для передачи значений.

Закрытие соединения

Когда работа с БД завершена, рекомендуется закрыть соединение. Соединение может быть закрыто с помощью метода close().

Чтобы закрыть соединение, используйте объект соединения с вызовом метода close() следующим образом:

con = sqlite3.connect('mydatabase.db')

#program statements

con.close()

SQLite3 datetime

В базе данных Python SQLite3 можно легко сохранять дату или время, импортируя Python модуль datetime.
Следующие форматы являются наиболее часто используемыми форматами для даты и времени:

YYYY-MM-DD

YYYY-MM-DD HH:MM

YYYY-MM-DD HH:MM:SS

YYYY-MM-DD HH:MM:SS.SSS

HH:MM

HH:MM:SS

HH:MM:SS.SSS

now

Рассмотрим следующий код:

import sqlite3

import datetime

con = sqlite3.connect('mydatabase.db')

cursorObj = con.cursor()

cursorObj.execute('create table if not exists assignments(id integer, name text, date date)')

data = [(1, "Ridesharing", datetime.date(2017, 1, 2)), (2, "Water Purifying", datetime.date(2018, 3, 4))]

cursorObj.executemany("INSERT INTO assignments VALUES(?, ?, ?)", data)

con.commit()

В этом коде модуль datetime импортируется
первым, далее создали таблицу с именем assignments с тремя столбцами.

Тип данных третьего столбца — дата. Чтобы вставить дату в столбец, воспользовались datetime.date.
Точно так же можно использовать datetime.time для обработки времени.

Вывод

SQLite можно использовать в своих разработках, но с учетом особенностей этой БД. SQLite прекрасно подойдет
для проектов у которых мало операций записи, не нужна система прав доступа к БД и ограниченны ресурсы сервера.

В прошлой статье мы рассказали про SQLite — простую базу данных, которая может работать почти на любой платформе. Теперь проверим теорию на практике: напишем простой код на Python, который сделает нам простую базу и наполнит её данными и связями.

Предыстория

Если это первая статья про базы данных, которую вы читаете, то лучше сделать так, а потом вернуться сюда:

  1. Почитать про виды баз данных и посмотреть на схему связей в реляционной базе данных. Там простая схема про магазин — в ней связаны товары, клиенты и покупки.
  2. Посмотреть, как работают SQL-запросы: что это такое, как база на них реагирует и что получается в итоге. В статье мы с помощью SQL-запросов сделали базу данных по магазинной схеме.

Создаём и наполняем базу данных SQLite в Python

Та самая схема базы данных простого магазина

Что будем делать

Сегодня мы сделаем то же самое, что и в SQL-запросах, но на Python, используя стандартную библиотеку sqlite3:

  • создадим базу и таблицы в ней;
  • наполним их данными;
  • создадим связи;
  • проверим, как это работает.

После этого мы сможем использовать такой же подход в других проектах и хранить все данные не в текстовых файлах, а в полноценной базе данных. 

Подключаем и создаём базу данных

За работу с SQLite в Python отвечает стандартная библиотека sqlite3:

# подключаем SQLite
import sqlite3 as sl

Теперь нам нужно указать файл базы данных, с которым мы будем дальше работать. Удобство библиотеки в том, что нам достаточно указать имя файла, а дальше будет такое:

  • если этого файла нет, то программа создаст пустую базу данных с таким именем;
  • если указанный файл есть, то программа подключится к нему и будет с ним работать.

Получается, нам неважно, есть файл с базой или нет — мы в любом случае после запуска получим то, что нам нужно. Для этого пишем команду:

# открываем файл с базой данных
con = sl.connect('thecode.db')

Мы указали, что файл называется thecode.db, без указания папок и дисков. Это значит, что файл с базой появится в той же папке, что и наш скрипт — можно в этом убедиться после запуска программы.

Создаём таблицу с товарами

У нас есть база, в которой можно создавать таблицы для хранения данных. Создадим первую таблицу для товаров:

with con:
    con.execute("""
        CREATE TABLE goods (
           product VARCHAR(20) PRIMARY KEY,
           count INTEGER,
           price INTEGER

);
    """)

Если посмотреть внимательно на код, можно заметить, что текст внутри кавычек полностью повторяет обычный SQL-запрос, который мы уже использовали в прошлой статье. Единственное отличие — в SQLite используется INTEGER вместо INT:

CREATE TABLE goods (
    product VARCHAR(20) PRIMARY KEY,
    count INT,
    price INT
);

Теперь соберём код вместе и запустим его ещё раз:

# подключаем SQLite
import sqlite3 as sl

# открываем файл с базой данных
con = sl.connect('thecode.db')

# создаём таблицу для товаров
with con:
    con.execute("""
        CREATE TABLE goods (
            product VARCHAR(20) PRIMARY KEY,
            count INTEGER,
            price INTEGER

);
    """)

Но после второго запуска компьютер почему-то выдаёт ошибку:

❌ sqlite3.OperationalError: table goods already exists

Дело в том, что при повторном запуске программа пытается создать таблицу с товарами, которая уже есть в базе. Так как имена таблиц совпадают, а двух одинаковых имён быть не может, отсюда и возникает ошибка.

Чтобы не попадать в такую ситуацию, добавим проверку: посмотрим, есть ли в базе нужная нам таблица или нет. Если нет — создаём, если есть — двигаемся дальше:

# открываем базу
with con:
    # получаем количество таблиц с нужным нам именем
    data = con.execute("select count(*) from sqlite_master where type='table' and name='goods'")
    for row in data:
        # если таких таблиц нет
        if row[0] == 0:
            
            # создаём таблицу для товаров
            with con:
                con.execute("""
                    CREATE TABLE goods (
                        product VARCHAR(20) PRIMARY KEY,
                        count INTEGER,
                        price INTEGER
                    );
                """)

Точно так же мы потом сделаем и с остальными таблицами — сразу встроим проверку, и если нужных таблиц не будет, то программа создаст их автоматически.

Теперь наполняем нашу таблицу товарами, используя стандартный SQL-запрос. Например, можно добавить два стола, которые стоят по 3000 ₽:

INSERT INTO goods SET
product = 'стол',
count = 2,
price = 3000;

Но добавлять записи по одному товару за раз — это долго и неэффективно. Проще сразу в одном запросе добавить все нужные товары: стол, стул и табурет:

# подготавливаем множественный запрос
sql = 'INSERT INTO goods (product, count, price) values(?, ?, ?)'
# указываем данные для запроса
data = [
    ('стол', 2, 3000),
    ('стул', 5, 1000),
    ('табурет', 1, 500)
]

# добавляем с помощью множественного запроса все данные сразу
with con:
    con.executemany(sql, data)

# выводим содержимое таблицы на экран
with con:
    data = con.execute("SELECT * FROM goods")
    for row in data:
        print(row)

В конце мы добавили вывод таблицы — так можно убедиться, что запрос сработал и данные отправились в базу в нужное место.

Создаём и наполняем базу данных SQLite в Python

Создаём и заполняем таблицу с товарами

Заведём таблицу clients для клиентов и заполним её точно так же, как мы это сделали с клиентской таблицей. Для этого просто копируем предыдущий код, меняем название таблицы и указываем правильные названия полей.Ещё посмотрите на отличие от обычного SQL в последней строке объявления полей таблицы: вместо id INT AUTO_INCREMENT PRIMARY KEY надо указать id INTEGER PRIMARY KEY. Без этого не будет работать автоувеличение счётчика.

# --- создаём таблицу с клиентами ---
# открываем базу
with con:
    # получаем количество таблиц с нужным нам именем — clients
    data = con.execute("select count(*) from sqlite_master where type='table' and name='clients'")
    for row in data:
        # если таких таблиц нет
        if row[0] == 0:

            # создаём таблицу для клиентов
            with con:
                con.execute("""
                    CREATE TABLE clients (
                        name VARCHAR(40),
                        phone VARCHAR(10) UNIQUE,
                       id INTEGER PRIMARY KEY
                    );
                """)
# подготавливаем множественный запрос
sql = 'INSERT INTO clients (name, phone) values(?, ?)'
# указываем данные для запроса
data = [
    ('Миша', 9208381096),
    ('Наташа', 9307265198),
    ('Саша', 9307281096)
]

# добавляем с помощью множественного запроса все данные сразу
with con:
    con.executemany(sql, data)

# выводим содержимое таблицы с клиентами на экран
with con:
    data = con.execute("SELECT * FROM clients")
    for row in data:
        print(row)

Cоздаём таблицу с покупками и связываем всё вместе

У нас всё готово для того, чтобы на основе первых двух таблиц создать третью — в ней будут данные сразу и о покупках, и о том, кто это купил. Если интересно, как это работает в деталях, — почитайте статью про связи в базе данных.

# --- создаём таблицу с покупками ---
# открываем базу
with con:
    # получаем количество таблиц с нужным нам именем — orders
    data = con.execute("select count(*) from sqlite_master where type='table' and name='orders'")
    for row in data:
        # если таких таблиц нет
        if row[0] == 0:

            # создаём таблицу для покупок
            with con:
                con.execute("""
                    CREATE TABLE orders (
                        order_id INTEGER PRIMARY KEY,
                        product VARCHAR,
                        amount INTEGER,
                        client_id INTEGER,
                        FOREIGN KEY (product) REFERENCES goods(product),
                        FOREIGN KEY (client_id) REFERENCES clients(id)
                    );
                """)

Проверим, что связь работает: добавим в таблицу с заказами запись о том, что Миша купил 2 табурета:

# подготавливаем  запрос
sql = 'INSERT INTO orders (product, amount, client_id) values(?, ?, ?)'
# указываем данные для запроса
data = [
    ('табурет', 2, 1)
]
# добавляем запись в таблицу
with con:
    con.executemany(sql, data)

# выводим содержимое таблицы с покупками на экран
with con:
    data = con.execute("SELECT * FROM orders")
    for row in data:
        print(row)

Компьютер выдал строку (1, ‘табурет’, 2, 1), значит, таблицы связались правильно.

Что дальше

Теперь, когда мы знаем, как работать с SQLite в Python, можно использовать эту базу данных в более серьёзных проектах:

  • хранить результаты парсинга;
  • запоминать отсортированные датасеты;
  • вести учёт пользователей и их действий в системе.

Подпишитесь, чтобы не пропустить продолжение про SQLite. А если вам интересна аналитика и работа с данными, приходите на курс «SQL для работы с данными и аналитики».

Вёрстка:

Кирилл Климентьев

Все, что вам нужно для начала работы!

SQL и Python быстро стали основными навыками для любого, кто серьезно занимается анализом данных! Это руководство по Python SQLite — единственное руководство, которое вам нужно для начала работы с SQLite на Python. В этом посте мы расскажем:

  • Загрузка библиотеки
  • Создание и подключение к вашей базе данных
  • Создание таблиц базы данных
  • Добавление данных
  • Запрос данных
  • Удаление данных
  • И многое другое!

SQLite3 (мы будем называть его просто SQLite) является частью стандартного пакета Python 3, поэтому вам не нужно ничего устанавливать. Если вы не используете Python 3, ознакомьтесь с этой ссылкой, чтобы начать работу.

Если вы хотите начать работу с SQL, ознакомьтесь с моим полным Учебником по SQL для начинающих, который включает бесплатный загружаемый PDF-файл и другие бесплатные материалы.

Что вы создадите

Следуя этому руководству, вы создадите базу данных в SQLite с помощью Python. В частности, этот пост проведет вас через все шаги по созданию базы данных, которая охватывает следующую таблицу, включая все отношения:

Типы данных, доступные в SQLite для Python

SQLite для Python предлагает меньше типов данных, чем другие реализации SQL. Это может немного ограничивать. Однако, как вы увидите, SQLite упрощает многие другие вещи. Давайте кратко рассмотрим доступные типы данных:

  • NULL — включает значение NULL.
  • INTEGER — включает целое число.
  • REAL — включает значение с плавающей точкой (десятичное).
  • ТЕКСТ. — Включает текст
  • BLOB. — Включает в себя большой двоичный объект, который хранится точно как вход

В этом списке вы можете заметить ряд отсутствующих типов данных, таких как даты. К сожалению, при использовании SQLite вы ограничены этими типами данных.

Начало работы с SQLite в Python

Начнем с загрузки учебника в библиотеке. Мы можем сделать это с помощью следующей команды:

import sqlite3

Давайте перейдем к созданию нашей базы данных.

Создание базы данных SQLite на Python

В этом разделе руководства Python SQLite мы рассмотрим различные способы создания базы данных на Python с помощью SQLite. Для этого мы создадим объект Connection, который будет представлять базу данных. Этот объект создается с помощью функции SQLite connect ().

Давайте сначала создадим файл .db, так как это очень стандартный способ поддержки базы данных SQLite. Мы представим соединение с помощью переменной с именем conn. Мы создадим файл с именем orders.db.

conn = sqlite3.connect('orders.db')

С помощью этой строки кода мы создали новый объект connection, а также новый файл с именем orders.db в каталоге, в котором вы работаете. Если вы хотите указать конкретный каталог, вы можете написать:

conn = sqlite3.connect(r'PATH-TO-YOUR-DIRECTORY/orders.db')

Если файл уже существует, функция connect просто подключится к этому файлу.

Примечание: обратите внимание, что мы включили букву r перед строкой, содержащей этот путь. Это позволяет Python знать, что мы работаем с необработанной строкой, а это означает, что / не будет использоваться для экранирования символов. Вы можете узнать больше о необработанных строках, просмотрев эту ссылку.

Функция connect создает соединение с базой данных SQLite и возвращает объект, представляющий его.

Базы данных в памяти

Другой способ создания баз данных с использованием SQLite в Python — это их создание в памяти. Это отличный способ создания баз данных, которые можно использовать в целях тестирования, поскольку они существуют только в оперативной памяти.

conn = sqlite3.connect(:memory:)

Однако для целей этого руководства и для большинства случаев использования, с которыми вы столкнетесь, вы будете использовать метод, который мы описали ранее.

Создание объекта курсора

Теперь, когда мы создали объект подключения к базе данных, наша следующая задача — создать объект курсор. Проще говоря, объект курсора позволяет нам выполнять SQL-запросы к базе данных. Мы создадим переменную cur для хранения объекта курсора:

cur = conn.cursor()

Теперь, когда у нас есть объект курсора, мы можем использовать его для выполнения SQL-запросов в следующем стиле:

cur.execute("YOUR-SQL-QUERY-HERE;")

Обратите внимание, что мы заключили наш SQL-запрос в кавычки — это важно. Не имеет значения, используем ли мы одинарные, двойные или тройные кавычки. Для более длинных запросов часто лучше использовать тройные кавычки, поскольку они позволяют нам писать многострочные запросы.

Создание наших таблиц в SQLite для Python

На этом этапе руководства Python SQLite давайте создадим нашу первую таблицу с использованием SQLite в Python! Теперь, когда у нас есть объект соединения (conn) и объект курсора (cur), мы можем создать нашу первую таблицу. Следуя схеме базы данных, которую мы показали ранее:

Начнем с таблицы users.

cur.execute("""CREATE TABLE IF NOT EXISTS users(
   userid INT PRIMARY KEY,
   fname TEXT,
   lname TEXT,
   gender TEXT);
""")
conn.commit()

В приведенном выше коде мы делаем несколько вещей:

  1. Использование функции execute в объекте курсора для выполнения SQL-запроса
  2. Использование SQL для создания таблицы с именем users
  3. ЕСЛИ НЕ СУЩЕСТВУЕТ поможет нам при повторном подключении к базе данных. Запрос позволит нам проверить, существует ли таблица, и если это так, ничего не изменится.
  4. Мы создаем четыре столбца: ИД пользователя, fname, lname и пол. ИД пользователя назначается первичным ключом.
  5. Мы зафиксировали изменения, используя функцию commit для объекта подключения.

Чтобы создать другую нашу таблицу, мы можем следовать аналогичному шаблону и написать следующие команды:

cur.execute("""CREATE TABLE IF NOT EXISTS orders(
   orderid INT PRIMARY KEY,
   date TEXT,
   userid TEXT,
   total TEXT);
""")
conn.commit()

После выполнения этих двух сценариев ваша база данных будет иметь две таблицы. Теперь мы готовы начать добавлять данные!

Добавление данных с помощью SQLite в Python

Давайте посмотрим, как добавить данные с помощью SQLite на Python в только что созданную базу данных. Подобно запросу создания таблицы, запрос на добавление данных использует объект курсора для выполнения запроса.

cur.execute("""INSERT INTO users(userid, fname, lname, gender) 
   VALUES('00001', 'Nik', 'Piepenbreier', 'male');""")
conn.commit()

Часто, когда мы работаем в Python, у нас есть переменные, которые содержат для нас значения. Например, у нас может быть кортеж, содержащий информацию о пользователе, которая может выглядеть так:

user = ('00002', 'Lois', 'Lane', 'Female')

Если бы мы хотели загрузить эти данные в нашу базу данных, мы бы использовали другое соглашение:

cur.execute("INSERT INTO users VALUES(?, ?, ?, ?);", user)
conn.commit()

Здесь мы заменили все значения вопросительными знаками и добавили дополнительный параметр, содержащий значения, которые мы надеемся добавить.

Здесь важно отметить, что SQLite ожидает, что значения будут в формате кортежа. Однако переменная может содержать список, если элементы списка являются кортежами. Например, мы могли бы добавить больше пользователей с помощью переменной:

more_users = [('00003', 'Peter', 'Parker', 'Male'), ('00004', 'Bruce', 'Wayne', 'male')]

В этом случае вместо функции execute нам нужно использовать функцию executemany:

cur.executemany("INSERT INTO users VALUES(?, ?, ?, ?);", more_users)
conn.commit()

Если бы мы использовали здесь функцию execute для объекта курсора, функция предполагала бы, что мы передаем два элемента в таблицу напрямую (два кортежа), а не два набора по четыре элемента в каждом! К счастью, в этом случае функция не сработала бы, но будьте осторожны с тем, какую функцию вы используете!

SQLite и предотвращение инъекционных атак

Между прочим, использование метода (?,?,…), О котором мы говорили выше, также помогает защитить от атак SQL-инъекций. По этой причине рекомендуется использовать этот метод вместо ранее упомянутого. Кроме того, печатать легче, так что это беспроигрышный вариант!

Некоторые сценарии для загрузки дополнительных данных

Если вы самостоятельно следите за учебным курсом Python SQLite, давайте загрузим еще несколько данных, чтобы сделать следующие разделы более содержательными. Ниже приведены сценарии, которые можно скопировать и вставить, чтобы вставить образцы данных в обе таблицы:

Вы можете загрузить эти данные, используя следующие запросы:

cur.executemany("INSERT INTO users VALUES(?, ?, ?, ?);", customers)
cur.executemany("INSERT INTO orders VALUES(?, ?, ?, ?);", orders)
conn.commit()

Выбор данных в SQLite с помощью Python

Далее в этом руководстве по Python SQLite мы рассмотрим, как выбирать данные с помощью SQLite в Python! Мы будем следовать той же структуре, что и для выполнения запросов выше, но мы также добавим к ней еще один элемент.

Использование fetchone () в SQLite с Python

Начнем с использования функции fetchone (). Мы создаем переменную one_result, чтобы вытащить только результат

cur.execute("SELECT * FROM users;")
one_result = cur.fetchone()
print(one_result)

Это возвращает:

[(1, 'Nik', 'Piepenbreier', 'male')]

Использование fetchmany () в SQLite с Python

Допустим, мы хотим вернуть более одного результата, мы могли бы использовать функцию fetchmany (). Давайте запустим другой скрипт, чтобы получить 3 результата:

cur.execute("SELECT * FROM users;")
three_results = cur.fetchmany(3)
print(three_results)

Это вернет следующее:

[(1, 'Nik', 'Piepenbreier', 'male'), (2, 'Lois', 'Lane', 'Female'), (3, 'Peter', 'Parker', 'Male')]

Использование fetchall () в SQLite с Python

Точно так же мы могли бы использовать функцию fetchall () для возврата всех результатов. Если бы мы выполнили следующее, все результаты были бы возвращены:

cur.execute("SELECT * FROM users;")
all_results = cur.fetchall()
print(all_results)

Удаление данных в SQLite с помощью Python

Теперь мы рассмотрим, как удалять данные с помощью SQLite в Python. Мы можем сделать это, используя структуру, аналогичную описанной выше. Допустим, мы хотим удалить любого пользователя с фамилией «Паркер», мы могли бы написать:

cur.execute("DELETE FROM users WHERE lname='Parker';")
conn.commit()

Когда мы затем запустим запрос ниже:

cur.execute("select * from users where lname='Parker'")
print(cur.fetchall())

Будет распечатан пустой список, подтверждающий, что запись была удалена.

Объединение таблиц с SQLite в Python

Наконец, давайте посмотрим, как объединить данные в более сложный запрос. Допустим, мы хотели сгенерировать запрос, который включает имя и фамилию каждого покупателя в каждом заказе.

Для этого напишем следующее:

cur.execute("""SELECT *, users.fname, users.lname FROM orders
    LEFT JOIN users ON users.userid=orders.userid;""")
print(cur.fetchall())

Точно так же вы можете применить некоторые другие уловки SQL. Чтобы получить полное представление о SQL, прочтите мое полное руководство для новичков здесь.

Заключение: Учебное пособие по Python SQLite

В этом руководстве по Python SQLite мы изучили все, что вам нужно знать, чтобы начать работу с SQLite в Python. Мы начали с того, как загрузить библиотеку, изучили, как создать базу данных и таблицы, как добавлять данные, как запрашивать таблицы и как удалять данные.

Понравилась статья? Поделить с друзьями:
  • Диоксидин ампулы инструкция по применению в нос детям отзывы
  • Руководство лянча дедра
  • Должностная инструкция заместителя директора института по общим вопросам
  • Амфотерицин мазь инструкция по применению цена
  • Фенигидин инструкция по применению цена отзывы аналоги таблетки взрослым