WEBのシステム開発はPHPを使用していますが、データ解析等のため Python3 の研究を始めました。Python3 は日本語の情報がとても少ないので、エンジニアや学生の皆さんに役立ちそうなことをブログ記事として共有できればと思います。
この記事では Python3 で SQLite3 に接続する方法、エラー処理(例外処理)、サンプルによるCRUD(※)、PHPer向け注意点についてまとめました。なおサンプルは Django 等、特定フレームワークの ORM ではなく、SQLの直接実行例です。
MySQL は Python3でMySQLを使う – 基本操作からエラー処理までサンプルコード付を参照ください。
目次
Python3 で SQLite3 を使うための準備
MySQL の場合にはパッケージをインストールする必要がありましたが、SQLite3 はPython3にはじめから組み込まれている標準モジュールがあるため、とくに何もすることはありません。
関連する公式ページ
http://docs.python.jp/3.5/library/sqlite3.html
では CRUD の操作をみていきます。
接続 / CREATE / INSERT
接続からテーブル作成・データ挿入まで、よくある操作をサンプルコードにまとめてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# Python 3.5.2 にて動作を確認 # sqlite3 標準モジュールをインポート import sqlite3 # データベースファイルのパス dbpath = 'sample_db.sqlite' # データベース接続とカーソル生成 connection = sqlite3.connect(dbpath) # 自動コミットにする場合は下記を指定(コメントアウトを解除のこと) # connection.isolation_level = None cursor = connection.cursor() # エラー処理(例外処理) try: # CREATE cursor.execute("DROP TABLE IF EXISTS sample") cursor.execute( "CREATE TABLE IF NOT EXISTS sample (id INTEGER PRIMARY KEY, name TEXT)") # INSERT cursor.execute("INSERT INTO sample VALUES (1, '佐藤')") # プレースホルダの使用例 # プレースホルダには疑問符(qmark スタイル)と名前(named スタイル)の2つの方法がある # 1つの場合には最後に , がないとエラー。('鈴木') ではなく ('鈴木',) cursor.execute("INSERT INTO sample VALUES (2, ?)", ('鈴木',)) cursor.execute("INSERT INTO sample VALUES (?, ?)", (3, '高橋')) cursor.execute("INSERT INTO sample VALUES (:id, :name)", {'id': 4, 'name': '田中'}) # 複数レコードを一度に挿入 executemany メソッドを使用 persons = [ (5, '伊藤'), (6, '渡辺'), ] cursor.executemany("INSERT INTO sample VALUES (?, ?)", persons) # わざと主キー重複エラーを起こして例外を発生させてみる cursor.execute("INSERT INTO sample VALUES (1, '中村')") except sqlite3.Error as e: print('sqlite3.Error occurred:', e.args[0]) # 保存を実行(忘れると保存されないので注意) connection.commit() # 接続を閉じる connection.close() |
ポイント解説
エラー処理
SQLite3 の操作上のエラーは sqlite3.Error により処理できます。データベースの操作に予期せぬエラーはつきものなので、必ず例外処理をしておきましょう。上のサンプルソースでもわざと不正なSQLを実行して例外を発生させています。
プレースホルダ
プレースホルダには疑問符(qmark スタイル)と名前(named スタイル)の2つの方法があります(上のサンプルコードを参照)。PHP の PDO や SQLite3 と同じですね。
PHPer 向け注意事項
PHP の PDO や SQLite3 は INSERT / UPDATE / DELETE 文の実行と同時にデータの更新が行われますが、Python3 の sqlite3 モジュールでは(上のサンプルコードの最終行のように)必ずコミットをする必要があります。connection.commit() を忘れるとデータが保存されないことに注意しましょう。
SELECT
SELECT文を使ってよくやることをまとめてみました。件数取得、全件データ取得、1件データ取得、WHERE句など大抵のことは下記サンプルでわかるかと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# SELECT cursor.execute('SELECT * FROM sample ORDER BY id') # 全件取得は cursor.fetchall() res = cursor.fetchall() print(res) # ((1, '佐藤'), (2, '鈴木'), (3, '高橋'), (4, '田中'), (5, '伊藤'), (6, '渡辺')) # rowcount プロパティーでは件数取得できないことに注意! # @see: http://docs.python.jp/3.5/library/sqlite3.html#sqlite3.Cursor.rowcount print(len(res)) # 6 print(cursor.rowcount) # -1 # 1件取得 cursor.fetchone() # fetchone() メソッド実行のたびにカーソル位置が移動します cursor.execute('SELECT * FROM sample ORDER BY id') print(cursor.fetchone()) # (1, '佐藤') print(cursor.fetchone()) # (2, '鈴木') print(cursor.fetchone()) # (3, '高橋') # WHERE 句の例 cursor.execute('SELECT * FROM sample WHERE name=?', ('佐藤',)) print(cursor.fetchone()) # (1, '佐藤') # WHERE 句で該当なしの場合 cursor.execute('SELECT * FROM sample WHERE name=?', ('SUZUKI',)) print(cursor.fetchall()) # [] print(cursor.fetchone()) # None # 全件ループ表示方法は「イテレータ」と「fetchall()」の2パターン。いずれも同じ結果が得られます。 # イテレータ for row in cursor.execute('SELECT * FROM sample ORDER BY id ASC'): print(row) # fetchall() cursor.execute('SELECT * FROM sample ORDER BY id ASC') for row in cursor.fetchall(): print(row) # いずれも下記の出力結果となります。 """ (1, '佐藤') (2, '鈴木') (2, '鈴木') (4, '田中') (5, '伊藤') (6, '渡辺') """ |
ポイント解説
カーソルオブジェクトの rowcount プロバティーは SELECT 文の件数取得には使えないことに注意しましょう。サンプルのように len() を使います。
全件をループする方法は上のコードのように「イテレータ」と「fetchall()メソッド」による2パターンがあります。どちらのパターンも覚えておきましょう。
PHPer 向け – 辞書型(連想配列)で取得するには?
PHP の PDO や SQLite3 の場合、結果セットは $row[‘name’] のように連想配列で受け取れますが、cursor.fetchone() , cursor.fetchall() ともに結果セットは 0 で始まる単純な配列(正確にはタプルというデータ型)になっています。PDO::FETCH_NUM, SQLITE3_NUM と同じ挙動です。
row[0], row[1] ではなく、row[‘id’], row[‘name’] のように結果セットを連想配列(Python では辞書型と呼びます)で受け取りたいケースも多いかと思います。
http://docs.python.jp/3.5/library/sqlite3.html#sqlite3.Connection.row_factory
上記公式ドキュメントのように辞書型で受け取る方法は2パターンで、どちらでも row[‘id’], row[‘name’] にて受け取れるようになります。
1. row_factory に sqlite3.Row を設定
コネクションオブジェクトの row_factory プロパティーに sqlite3.Row セットする方法です。一行で済むのでオススメです。
1 2 3 4 |
connection = sqlite3.connect(dbpath) # カーソル生成前に row_factory = sqlite3.Rowをセット connection.row_factory = sqlite3.Row cursor = connection.cursor() |
2. row_factory に 独自実装の辞書を設定
コネクションオブジェクトの row_factory プロパティーに独自実装の辞書をセットする方法です。
1 2 3 4 5 6 7 8 9 |
def dict_factory(cursor, row): d = {} for idx, col in enumerate(cursor.description): d[col[0]] = row[idx] return d connection = sqlite3.connect(dbpath) connection.row_factory = dict_factory cursor = connection.cursor() |
UPDATE / DELETE
UPDATE と DELETE には特別なことはありません。上の INSERT と同様にコミットしないと変更が保存されないこと、適宜 sqlite3.Error で例外処理をすることを忘れないようにしましょう。
1 2 3 4 5 6 7 8 |
# UPDATE cursor.execute('UPDATE sample SET name=? WHERE id=1', ('小林',)) cursor.execute('UPDATE sample SET name=? WHERE id=?', ('加藤', 2)) connection.commit() # DELETE cursor.execute('DELETE FROM sample WHERE id > 3') connection.commit() |
以上、Python3 で SQLite を使う方法をまとめてみました。インターフェースこそ MySQL と SQLite で同様ですが、プレースホルダやSELECT結果の件数取得など細かい使い方が異なっているので注意しましょう。
※弊社の専門はPHP言語なので、おかしなところがあればご指摘ください。
※この記事の内容は適宜更新することがあります。