PythonでSQLite3のデータベース、テーブルの作成やデータの取得のやり方を解説する

スポンサーリンク

Python SQLite モジュールは、SQL 型のデータベース管理というしばしば困難なタスクを簡単に実行する方法を提供する軽量なライブラリです。

他のデータベースシステムとは異なり、専用のサーバプロセス/マシンを必要としません。

これは、データベース管理のために使いやすいSQLタイプのクエリを組み合わせ、最もPythonicな方法で、オブジェクトの内部ストレージに使用します。

さっそくこのライブラリを使って、私たちのアプリケーションのための独自のデータベースを作ってみましょう。

スポンサーリンク

Python SQLite

Python SQLiteはインストールされたどのバージョンのPythonにも付属しているので、 pip でインストールする必要はありません。

そうです、すでに持っているのです。

Python3を使っているので、インポートするために、sqlite3モジュールをインポートします。

import sqlite3

それでは、メインのモジュールメソッドから見ていきましょう。

データベースの作成

外部サーバを起動せず、すべて現在のマシンの中にあると言いましたが、これはデータベースシステムの標準プロトコルなので、このモジュールもそうすることでそのように動作します!

Python SQLite データベースへの接続を作成します。

これはデータベース用のメモリを確保し、データベースファイルからデータを取得するだけであり、データベースは db ファイルから構築されます。

import sqlite3
# Establish a connection to the Database and create
# a connection object
conn = sqlite3.connect('database.db')

ここで、database.dbはデータベースファイルであり、ここにデータが格納される。

したがって、このファイルからデータベースを呼び出す。

注意: このファイルが存在しない場合、データベースは自動的にファイルを作成し、次回以降のデータベースの更新にそのファイルを使用します。

すでにこのファイルがある場合は、誤って上書きしてしまわないように注意しなければなりません。

そこで、以下の関数を使って、そのファイルがすでにシステム内に存在するかどうかを確認する必要があります。

import os
 
def check_db(filename):
    return os.path.exists(filename)

しかし、単に一時的なデータベースが欲しいだけなら、:memory:という特殊なファイルを使ってRAM上に直接データベースを構築する方法もある。

import sqlite3
conn = sqlite3.connect(':memory:')

上記の方法の問題点は、最後に conn.close() を使って明示的に接続を閉じる必要があることです。

Python にはコンテキストマネージャという非常に優れたソリューションがあります。

コンテキストマネージャは with ステートメントを使うと、自動的にそれを行ってくれます。

import sqlite3
 
db_file = 'database.db'
with sqlite3.connect(db_file) as conn:
    print('Created the connection!')
print('Automatically closed the connection!')

結果は以下の通りです。

Created the connection!
Automatically closed the connection!

カーソルオブジェクトの作成

接続が確立されると、接続オブジェクトが生成され、そこから Cursor オブジェクトを作成することができます。

# Create a cursor to the Database
c = conn.cursor()

このカーソルはデータベースへのポインターであり、データベースを操作して場所を移動したり SQL クエリーを実行したりするのに使われます。

データベーススキームの作成

クエリを実行する前に、まずレコードの格納方法に基づいたスキーマを作成する必要があります。

これはデータベーステーブルと呼ばれるもので、行と列を持つ構造体です。

行は実際のデータ値に対応し、列はその属性名に対応します。

画像を格納するための簡単なスキーマを作成してみましょう。

画像は「名前」「サイズ」「作成日」を持つものとして定義します。

実際のデータは、メモリ上のどこかにある。

スキーマはデータがどのように構成されるかを定義するだけです。

CREATE TABLE images(
    name text primary key,
    size text,
    date date
);

このようにテーブルを定義していくので、テーブルのスキーマは下図のようになります。

import sqlite3
import os
 
def check_db(filename):
    return os.path.exists(filename)
 
db_file = 'database.db'
schema_file = 'schema.sql'
 
if check_db(db_file):
    print('Database already exists. Exiting...')
    exit(0)
 
with open(schema_file, 'r') as rf:
    # Read the schema from the file
    schema = rf.read()
 
with sqlite3.connect(db_file) as conn:
    print('Created the connection!')
    # Execute the SQL query to create the table
    conn.executescript(schema)
    print('Created the Table! Now inserting')
    conn.executescript("""
                       insert into images (name, size, date)
                       values
                       ('sample.png', 100, '2019-10-10'),
                       ('ask_python.png', 450, '2019-05-02'),
                       ('class_room.jpeg', 1200, '2018-04-07');
                       """)
    print('Inserted values into the table!')
print('Closed the connection!')

カーソルを使ってSQLクエリを実行するには、cursor.execute('SQL_QUERY')にSQLクエリを渡してください。

このスキーマを作成するためのSQLクエリを書いてみましょう。

Created the connection!
Created the Table! Now inserting
Inserted values into the table!
Closed the connection!

このクエリは文字列として渡すこともできますが、より長いクエリを実行したい場合は、cursor.executescript() を使って .sql ファイルを作成し、そのファイルから読み込む方が簡単です。

それでは、schema.sqlというファイルにクエリを記述して、そこから読み込むことにしよう。

import sqlite3
 
db_file = 'database.db'
 
with sqlite3.connect(db_file) as conn:
    cursor = conn.cursor()
    cursor.execute("""
                   select * from images
                   """)
    for row in cursor.fetchall():
        name, size, date = row
        print(f'{name} {size} {date}')

結果は以下の通りです。

sample.png 100 2019-10-10
ask_python.png 450 2019-05-02
class_room.jpeg 1200 2018-04-07

テーブルから値を取得する

さて、テーブルに初期値を設定したので、テーブルのすべての行を取得するためにクエリを発行してみましょう。

カーソルオブジェクトをそのまま出力することはできないので、 cursor.fetchall() を使って明示的に属性を取得し、それを反復処理することで出力する必要があります。

import sqlite3
 
db_filename = 'database.db'
 
def display_table(conn):
    cursor = conn.cursor()
    cursor.execute('select name, size, date from images;')
    for name, size, date in cursor.fetchall():
        print(name, size, date)
 
 
with sqlite3.connect(db_filename) as conn1:
    print('Before changes:')
    display_table(conn1)
 
    cursor1 = conn1.cursor()
    cursor1.execute("""
    insert into images (name, size, date)
    values ('JournalDev.png', 2000, '2020-02-20');
    """)
 
    print('
After changes in conn1:'
)
    display_table(conn1)
 
    print('
Before commit:'
)
    with sqlite3.connect(db_filename) as conn2:
        display_table(conn2)
 
    # Commit from the first connection
    conn1.commit()
    print('
After commit:'
)
    with sqlite3.connect(db_filename) as conn3:
        display_table(conn3)
 
    cursor1.execute("""
    insert into images (name, size, date)
    values ('Hello.png', 200, '2020-01-18');
    """)
 
    print('
Before commit:'
)
    with sqlite3.connect(db_filename) as conn2:
        display_table(conn2)
 
    # Revert to changes before conn1's commit
    conn1.rollback()
    print('
After connection 1 rollback:'
)
    with sqlite3.connect(db_filename) as conn4:
        display_table(conn4)

結果は以下の通りです。

Before changes:
sample.png 100 2019-10-10
ask_python.png 450 2019-05-02
class_room.jpeg 1200 2018-04-07
 
After changes in conn1:
sample.png 100 2019-10-10
ask_python.png 450 2019-05-02
class_room.jpeg 1200 2018-04-07
JournalDev.png 2000 2020-02-20
 
Before commit:
sample.png 100 2019-10-10
ask_python.png 450 2019-05-02
class_room.jpeg 1200 2018-04-07
 
After commit:
sample.png 100 2019-10-10
ask_python.png 450 2019-05-02
class_room.jpeg 1200 2018-04-07
JournalDev.png 2000 2020-02-20
 
Before commit:
sample.png 100 2019-10-10
ask_python.png 450 2019-05-02
class_room.jpeg 1200 2018-04-07
JournalDev.png 2000 2020-02-20
 
After connection 1 rollback:
sample.png 100 2019-10-10
ask_python.png 450 2019-05-02
class_room.jpeg 1200 2018-04-07
JournalDev.png 2000 2020-02-20

SQLite のトランザクション

トランザクション管理は SQL データベースの機能の一つであり、SQLite でもトランザクションを扱います。

トランザクションとは、基本的には、クエリを実行して commit を置くことで、データベースを安全に変更することができる一連の変更のことです。

もし何らかの理由でコミットの直前にトランザクションを完了させたくない場合は、 rollback を使ってコミット前の状態に戻ることができる。

同様に、このような変更を通じて、データベースの状態を見ることもできます。

Db Table
Db Table

結果は以下の通りです。

Image Table
Image Table

ここでは、明示的にトランザクションを完了させた後にのみ、テーブルが変更されることがわかります。

それ以前の変更は、実際にはテーブルを変更しません。

最後に、Hello.pngレコードをロールバックし、テーブルに挿入されないようにします。

まとめ

SQL 型のデータベースシステムを Python の sqlite3 で簡単に利用する方法について、良いアイデアを得ることができたと思います。


タイトルとURLをコピーしました