PythonでSQLite3(エスキューライト)でデータベースを扱う方法を紹介します。SQLite3は軽量でコンパクトなファイルベースのリレーショナルデータベースシステムです。
はじめに
SQLite3のインストール
Macで初めからインストールされています。
ターミナスでインストールされているか確認しましょう。
以下のコマンドでバーションを確認することでインストールされているかわかります。
sqlite3 -version
3.28.0 2019-04-15 14:49:49
Windowsの場合は以下よりダウンロードしてインストールしてください。
「Precompiled Binaries for Windows」の「64-bit DLL (x64) for SQLite」をダウンロードして解凍します。
Pythonのパッケージのインストール
SQLite3は標準パッケージですので、インストールは不要です。
sqlite3をインポート
import sqlite3
本ページではインポートされている前提で紹介します。
参考サイト
SQLite 公式サイト
SQLite Tutorial
Python sqlite3
SQLiteのGUIの管理ツール
定番の管理ツールとして、DB Browser for SQLiteがあります。
Windowsだけでなく、MacやLinuxなどでも利用できます。
公式サイト
SQLite3の操作の基本
データベースに接続
connection = sqlite3.connect(dbpath)
dbpath
は任意のデータベースのファイル名とそのパスを設定してください。- ファイルが存在しない場合は空のデータベースのファイルを作成します。
Cursorオブジェクトを作成
cursor = connection.cursor()
Cursorオブジェクトは主に以下のような機能があります。
- execute:SQL 文を実行します。
- fetchone:クエリ結果から1つのシーケンスを返します。
- fetchall:全てのクエリ結果をリストで返します。
- close:接続を閉じます。
トランザクションをコミット
connection.commit()
SQLite3ではコミットしないとデータが反映されません。
(コミットしなくても反映させる方法はあるのですが、コミットを利用するようにしたほうが良いでしょう)
データベースを切断
connection.close()
データベースを作成
データベースの作成
import sqlite3 dbpath = "./log.sqlite" connection = sqlite3.connect(dbpath) cursor = connection.cursor() sql = """ CREATE TABLE IF NOT EXISTS Log ( id INTEGER PRIMARY KEY AUTOINCREMENT, dates TIMESTAMP, messages TEXT ) """ cursor.execute(sql) connection.close()
CREATE TABLE IF NOT EXISTS テーブル名(フィールド名 データ型, )
IF NOT EXISTS
:テーブルが存在しない場合は作成させます。これは無くてもいいです。- 変数にSQL文を代入しているのですが、長くなるので ダブルクォーテーションを3つ(
"""
)で囲むと改行が自由になります。
利用できるフィールドのデータ型
- INTEGER:整数。値の大きさに応じて、1、2、3、4、6、または8バイトに格納されます。
- REAL:浮動小数点。8バイトのIEEE浮動小数点数として格納されます。
- TEXT:テキスト。文字コードの対応はUTF-8、UTF-16BE、UTF-16LEのみ
- BLOB:なんでも。入力されたとおりに格納されます。
補足
- Boolean型はない。
- DateやTime型はない。
PythonのAPIによってTIMESTAMP型の指定は可能です。しかしTIMESTAMP
として扱われるのではなく、文字列として保存しています。そのためTIMESTAMP
として指定しても自動的に挿入されることはありません。空の場合はNULL
となります。
レコードを登録(挿入)
from datetime import datetime connection = sqlite3.connect(dbpath) cursor = connection.cursor() now = datetime.now() messages = "TEST" sql = "INSERT INTO Log (dates,messages) VALUES (?, ?)" cursor.execute(sql, (now, messages)) connection.commit() connection.close()
sql = "INSERT INTO テーブル名 (フィールド名1,フィールド名2) VALUES (?, ?)"
- sqlにSQL文を代入します。
- 値は
?
とします。
cursor.execute(sql, (値1, 値2))
- cursorのexecuteでSQL文を実行します。
- 値はタプル型でまとめます。
登録するフィールドが一つの場合
sql = "INSERT INTO テーブル名 (フィールド名) VALUES (?)"
cursor.execute(sql, (値, ))
(messages, )
のように、終わりにもカンマが必要です。カンマがないとエラーになります。
追加したレコードのIDを取得
cursor.lastrowid
にて取得することができます。
connection = sqlite3.connect(dbpath) cursor = connection.cursor() now = datetime.now() messages = "TEST" sql = "INSERT INTO Log (dates,messages) VALUES (?, ?)" cursor.execute(sql, (now, messages)) lastrowid = cursor.lastrowid connection.commit() sql = "SELECT * from Log where id = {}".format(lastrowid) cursor.execute(sql) data = cursor.fetchone() connection.close() print(data) # (6, '2020-10-10 13:38:48.551200', 'TEST')
レコードを更新
connection = sqlite3.connect(dbpath) cursor = connection.cursor() id = 1 messages = "TEST2" sql = "UPDATE Log SET messages = ? where id = ?" cursor.execute(sql, (messages, id)) connection.commit() connection.close()
sql = "UPDATE Log SET フィールド名 = ? where キーのフィールド名 = ?"
- sqlにSQL文を代入します。
where
で条件を決めます。- キーと値は
?
とします。
cursor.execute(sql, (messages, id))
- cursorのexecuteでSQL文を実行します。
レコードの検索
単一のフィールドを1件
connection = sqlite3.connect(dbpath) cursor = connection.cursor() sql = "SELECT id from Log" cursor.execute(sql) data = cursor.fetchone() connection.commit() connection.close() print(data) # (1,)
cursor.fetchone()
- 検索結果から初めの1つのシーケンスを返します。
全てのフィールドを全件取得
connection = sqlite3.connect(dbpath) cursor = connection.cursor() sql = "SELECT * from Log" cursor.execute(sql) data = cursor.fetchall() connection.commit() connection.close() print(data) # [(1, '2020-07-08 17:57:33.304128', 'TEST2'), (2, None, 'TEST')]
cursor.fetchall()
- 全ての検索結果をリストで返します。
For文で値を取得
connection = sqlite3.connect(dbpath) cursor = connection.cursor() sql = "SELECT * from Log" cursor.execute(sql) for data in cursor.fetchall(): print(data) connection.commit() connection.close() # (1, '2020-07-08 16:37:25.783336', 'TEST2') # (2, '2020-07-08 16:37:34.170706', 'TEST')
単一の条件で全件を取得
connection = sqlite3.connect(dbpath) cursor = connection.cursor() id = 2 sql = "SELECT * from Log where id = ?" cursor.execute(sql, (id,)) for data in cursor.fetchall(): print(data) connection.commit() connection.close() # (2, None, 'TEST')
複数の条件で全件を取得
connection = sqlite3.connect(dbpath) cursor = connection.cursor() id = 2 messages = "TEST" sql = "SELECT * from Log where id = ? and messages = ?" cursor.execute(sql, (id,messages)) for data in cursor.fetchall(): print(data) connection.commit() connection.close() # (2, None, 'TEST')
合計値を取得
sum(フィールド名)
で取得することができます。
where文
で条件を付けた場合など、検索対象がない場合の返り値は以下のようになります。0
でもなく、None
でもなく、(None,)
となりますので、注意してください。
(None,)
connection = sqlite3.connect(dbpath) cursor = connection.cursor() sql = "SELECT sum(id) from Log" cursor.execute(sql) data = cursor.fetchone() connection.close() print(data) # (21,)
最大値・最小値を検索(取得)
max(フィールド名), min(フィールド名)
で取得することができます。
connection = sqlite3.connect(dbpath) cursor = connection.cursor() sql = "SELECT max(dates), min(dates) from Log" cursor.execute(sql) data = cursor.fetchone() connection.close() print(data) # ('2020-10-10 13:38:48.551200', '2020-07-08 17:57:33.304128')
最大値・最小値のレコードを検索
最大値・最小値の取得の応用になりますが、where
に最大値・最小値を取得するSQL文を設定します。
以下は最大値のサンプルですが、最小値にする場合は、min
としてください。
connection = sqlite3.connect(dbpath) cursor = connection.cursor() sql = "SELECT *from Log where dates = (SELECT max(dates) from Log)" cursor.execute(sql) data = cursor.fetchone() connection.close() print(data) # (6, '2020-10-10 13:38:48.551200', 'TEST')
LIKE(ワイルドカード)で検索
connection = sqlite3.connect(dbpath) cursor = connection.cursor() messages = "TE_T%" sql = "SELECT * from Log where messages LIKE ?" cursor.execute(sql, (messages,)) for data in cursor.fetchall(): print(data) connection.commit() connection.close() # (1, '2020-07-08 17:57:33.304128', 'TEST2') # (2, None, 'TEST')
LIKE
を使用します。%
で前方・後方を任意に_
で文字列の一文字を任意にできます。複数文字の場合はその分の_
を挿入します。
NULLを検索
connection = sqlite3.connect(dbpath) cursor = connection.cursor() sql = "SELECT * from Log where dates is NULL" cursor.execute(sql) for data in cursor.fetchall(): print(data) connection.commit() connection.close() # (2, None, 'TEST')
フィールド名 is NULL
とします。
日付の検索
connection = sqlite3.connect(dbpath) cursor = connection.cursor() dates = "2020-07-08" sql = "SELECT * from Log where dates >= ?" cursor.execute(sql, (dates, )) for data in cursor.fetchall(): print(data) connection.commit() connection.close() # (1, '2020-07-08 17:57:33.304128', 'TEST2')
- SQLite3では厳密には日付や日時型のデータ型は存在しませんが、擬似的に検索することができます。
検索結果のレコードを連想配列で取得
connection = sqlite3.connect(dbpath) connection.row_factory = sqlite3.Row cursor = connection.cursor() sql = "SELECT * from Log" cursor.execute(sql) for data in cursor.fetchall(): print(data["id"], data["dates"], data["messages"]) connection.commit() connection.close() # 1 2020-07-08 17:57:33.304128 TEST2 # 2 None TEST
connection.row_factory = sqlite3.Row
- この一文を入れることにより、連想配列で取得することができます。
- それぞれの意味を理解するのは難しいので、ここでは説明しません。気になる方は以下を参照してください。
data = cursor.fetchall()
としてprint(data)
すると、以下のように表示されるので注意してください。[<sqlite3.Row object at 0x110c30bf0>, <sqlite3.Row object at 0x110c30e50>]
検索結果の件数を取得
connection = sqlite3.connect(dbpath) cursor = connection.cursor() id = 1 dates = "2020-07-08" sql = "SELECT * from Log where id = ? and dates >= ?" cursor.execute(sql, (id, dates)) data = cursor.fetchall() connection.commit() connection.close() print(data) # [(1, '2020-07-08 17:57:33.304128', 'TEST2')] print(len(num)) # 2
- SQLite3では件数を取得する関数が用意されていないため、
fetchall()
で全件取得してリスト型の件数を取得する必要があります。
レコードを削除
connection = sqlite3.connect(dbpath) cursor = connection.cursor() id = 2 sql = "DELETE from Log where id = ?" cursor.execute(sql, (id, )) connection.commit() connection.close()
テーブルを削除
connection = sqlite3.connect(dbpath) cursor = connection.cursor() cursor.execute("DROP TABLE IF EXISTS Log") connection.close()
Pandasデータフレーム
Pandasデータフレームからテーブルを作成
df.to_sql('テーブル名', connection, if_exists='replace')
if_exists='replace'
:もし同一テーブル名が存在していたら置き換える。- データベースのインデックスを指定する場合は、予めPandasデータフレームでインデックスを指定すると引き継がれます。
import sqlite3 import pandas as pd dbpath = "./log.sqlite" connection = sqlite3.connect(dbpath) cursor = connection.cursor() df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns = ["aaa", "bbb", "ccc"]) print(df) # aaa bbb ccc # 0 1 2 3 # 1 4 5 6 # 2 7 8 9 df.to_sql('test', connection, if_exists='replace') sql = 'SELECT * FROM test' for row in cursor.execute(sql): print(row) # (0, 1, 2, 3) # (1, 4, 5, 6) # (2, 7, 8, 9) df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns = ["aaa", "bbb", "ccc"]) df = df.set_index('aaa') print(df) # bbb ccc # aaa # 1 2 3 # 4 5 6 # 7 8 9 df.to_sql('test', connection, if_exists='replace') sql = 'SELECT * FROM test' for row in cursor.execute(sql): print(row) # (1, 2, 3) # (4, 5, 6) # (7, 8, 9) cursor.close() connection.close()
SQLiteのデータをPandasデータフレームで取得
pd.read_sql(sql, connection)
- インデックスの指定:
index_col='index'
import sqlite3 import pandas as pd dbpath = "./log.sqlite" connection = sqlite3.connect(dbpath) sql = 'SELECT * FROM test' df = pd.read_sql(sql, connection) print(df) # index aaa bbb ccc # 0 0 1 2 3 # 1 1 4 5 6 # 2 2 7 8 9 df = pd.read_sql(sql, connection, index_col='index') print(df) # aaa bbb ccc # index # 0 1 2 3 # 1 4 5 6 # 2 7 8 9 connection.close()
コメント