1. テーブル定義,テーブル生成,問い合わせ(SQLite3, Python を使用)

概要

Python言語からリレーショナルデータベースを操作する方法について説明する.リレーショナルデータベースは,複数のテーブルから構成される.テーブルは,数値,文字列,日時などの情報を行と列の形式で格納するデータ構造である.リレーショナルデータベースを操作する言語の世界標準がSQL(Structured Query Language)である.本教材では,PythonとSQLを組み合わせてデータベース操作を行う.データベースへの接続時には,データベース名(SQLite3ではデータベースファイルのパス)を指定する.

テーブル

リレーショナルデータベースでは,データベースをテーブルの集まり(collection of tables)として表現する.各テーブルにはテーブル名があり,テーブル内の各列には列名がある.テーブル名と列名は,テーブルや列を識別するために用いられる.

テーブルの例

idsepal_lengthsepal_widthpetal_lengthpetal_widthspecies
15.13.51.40.2Iris-setosa
24.93.01.40.2Iris-setosa
34.73.21.30.2Iris-setosa
44.63.11.50.2Iris-setosa
55.03.61.40.2Iris-setosa

リレーションスキーマ

リレーションスキーマ(スキーマともいう,relation schema)とは,テーブルの構造を形式的に表現したものである.Rをテーブル名,A1, A2, …, Anを属性名(列名)とするとき,リレーションスキーマを「R(A1, A2, …, An)」と記述する.本教材で使用するirisテーブルのリレーションスキーマは「iris(id, sepal_length, sepal_width, petal_length, petal_width, species)」である.

テーブル定義

テーブル定義とは,テーブル名,属性名の並び,各属性のデータ型,各属性の制約(例:主キー)を記述することである.

SQLのデータ型

SQLiteにおける代表的なデータ型を以下に示す.

データ型説明
INTEGER符号付き整数(signed integer)
REAL浮動小数点数(floating point value)
TEXT文字列(text string)

主キー

テーブルの行を一意に識別できる属性または属性の組のうち,極小なもの(不要な属性を含まないもの)を候補キー(candidate key)という.候補キーの中から,リレーションスキーマの設計時に,データベース管理者が管理上適切と判断し,かつ空値(NULL)をとる可能性がないものとして選定したものが主キー(primary key)である.

SQLの集約関数

SQLiteの代表的な集約関数を以下に示す.集約関数は,複数行のデータをまとめて1つの値を返す関数である.

集約関数説明
SUM()指定した属性の合計値
AVG()指定した属性の平均値
COUNT()行数
MAX()指定した属性の最大値
MIN()指定した属性の最小値

CSVファイル(CSV File)

CSV(Comma-Separated Values)ファイルとは,値をカンマで区切って並べたテキスト形式のデータファイルである.CSVファイルの列名は,データベースのテーブル定義における列名と異なる場合がある.

本教材では,Irisデータセット(150件のアヤメの計測データ)を使用する.本演習で取得するCSVファイルのヘッダー行の列名は sepal_length,sepal_width,petal_length,petal_width,species であり,id 列は含まれない.ファイルの内容は以下のとおりである.

sepal_length,sepal_width,petal_length,petal_width,species
5.1,3.5,1.4,0.2,setosa
4.9,3.0,1.4,0.2,setosa
4.7,3.2,1.3,0.2,setosa
4.6,3.1,1.5,0.2,setosa
5.0,3.6,1.4,0.2,setosa
5.4,3.9,1.7,0.4,setosa
4.6,3.4,1.4,0.3,setosa
5.0,3.4,1.5,0.2,setosa

Pythonの繰り返し処理

Pythonでは,データの集まりに対して for 文で各要素を順に処理できる.以下の例では,変数 rowt の各要素を順に参照する.

for row in t:
    print(row)

PythonのSQLプレースホルダー

SQL文中にプレースホルダーを示す記号「?」を記述し,実行時に指定した値で置き換えることができる.これはPythonの sqlite3 モジュールが提供する機能である.以下の例では,「?」の部分が値 4 で置き換えられ,"select * from iris where id = 4" に相当するSQL文が実行される.プレースホルダーを使用することで,SQLインジェクション(外部からの入力を利用してSQL文を改ざんする攻撃)を防止できる.

sql = "select * from iris where id = ?"
conn.execute(sql, (4,))

演習準備

本演習では Python を使用する.以下のやり方が分からない場合は,先に「Windows環境でのPython:基本とプログラムの作成・実行」を参照すること.

掲載されているPythonコードは,Windows 上の Python および Google Colab のいずれの環境でも動作する.Windows で実行する場合は,下記の「Python 3.12 のインストール(Windows 上)」と「必要なライブラリのインストール」を実施すること.Google Colab で実行する場合は,sqlite3pandasurllib.request はあらかじめ利用可能であり,追加インストールは不要である.

Python 3.12 のインストール(Windows 上) [クリックして展開]

以下のいずれかの方法で Python 3.12 をインストールする.Python がインストール済みの場合,この手順は不要である.

方法1:winget によるインストール

管理者権限コマンドプロンプトで以下を実行する.管理者権限のコマンドプロンプトを起動するには,Windows キーまたはスタートメニューから「cmd」と入力し,表示された「コマンドプロンプト」を右クリックして「管理者として実行」を選択する.

winget install --id Python.Python.3.12 -e --scope machine --silent --accept-source-agreements --accept-package-agreements --override "/quiet InstallAllUsers=1 PrependPath=1 Include_test=0 Include_pip=1 Include_launcher=1 InstallLauncherAllUsers=1 TargetDir=\"C:\Program Files\Python312\""
powershell -Command "$p='C:\Program Files\Python312'; $s=\"$p\Scripts\"; $m=[Environment]::GetEnvironmentVariable('Path','Machine'); if($m -notlike \"*$s*\") { [Environment]::SetEnvironmentVariable('Path', \"$p;$s;$m\", 'Machine') }"

--scope machine を指定することで,システム全体(全ユーザー向け)にインストールされる.このオプションの実行には管理者権限が必要である.インストール完了後,コマンドプロンプトを再起動すると PATH が反映される.

方法2:インストーラーによるインストール

  1. Python 公式サイト(https://www.python.org/downloads/)にアクセスし,「Download Python 3.x.x」ボタンから Windows 用インストーラーをダウンロードする.
  2. ダウンロードしたインストーラーを実行する.
  3. 初期画面の下部に表示される「Add python.exe to PATH」にチェックを入れてから「Customize installation」を選択する.このチェックを入れない場合,コマンドプロンプトから python コマンドを実行できない.
  4. 「Install Python 3.xx for all users」にチェックを入れ,「Install」をクリックする.

インストールの確認

コマンドプロンプトで以下を実行する.

python --version

バージョン番号(例:Python 3.12.x)が表示されればインストール成功である.「'python' は,内部コマンドまたは外部コマンドとして認識されていません.」と表示される場合は,インストールが完了していない.

必要なライブラリのインストール

管理者権限コマンドプロンプトで以下を実行する.管理者権限のコマンドプロンプトを起動するには,Windows キーまたはスタートメニューから「cmd」と入力し,表示された「コマンドプロンプト」を右クリックして「管理者として実行」を選択する.--no-user オプションは,ユーザーローカル領域ではなくシステム全体(全ユーザー向け)にインストールするための指定である.

pip install -U --no-user pandas

演習1.SQLite3によるテーブル定義,データ挿入,問い合わせ

本演習では,テキストエディタで Python スクリプトを作成し,コマンドプロンプトから実行して結果を確認する.スクリプトは段階的に作成し,各段階の追記後に実行して結果を確認する.スクリプトファイル名は iris_db.py とする.作業ディレクトリ(プログラムを保存し実行するフォルダ)は任意の場所(例:C:\work)とする.Google Colab を使用する場合は,各段階のコードをセルに追記して実行する.

手順

①〜⑦の各手順では,iris_db.py に以下のコードを追記し,コマンドプロンプトで python iris_db.py により実行する.①の段階で最初に実行する.

① カレントディレクトリの確認

カレントディレクトリ(プログラムを実行した時点の作業ディレクトリ)を取得して表示する.このディレクトリが,これ以降に作成するデータベースファイルやCSVファイルの保存場所となる.

import os
print(os.getcwd())

② iris.csv のダウンロード

Python の標準ライブラリ urllib.request を使用して,GitHub 上で公開されている Iris データセットの CSV ファイルをダウンロードする.urllib.request.urlretrieve(URL, ファイル名) は,URL から取得した内容を,指定したファイル名でカレントディレクトリに保存する.

import urllib.request
url = "https://gist.githubusercontent.com/curran/a08a1080b88344b0c8a7/raw/0e7a9b0a5d22642a06d3d5b9bcbad9890c8ee534/iris.csv"
urllib.request.urlretrieve(url, "iris.csv")

実行後,カレントディレクトリに iris.csv が保存される.このファイルには 150 件の Iris(アヤメ)のデータが含まれており,ヘッダー行の列名は sepal_length,sepal_width,petal_length,petal_width,species である.

③ データベースのテーブル定義

sqlite3.connect(ファイル名) でSQLite3データベースに接続し,接続オブジェクト conn を取得する.SQLite3はファイルベースのデータベースであるため,接続時にデータベースファイルのパス(ここでは 'hoge.sqlite')を指定する.ファイルが存在しない場合は新規作成される.接続オブジェクトはSQL文の実行やトランザクション(一連のデータベース操作をまとめて確定または取り消す仕組み)の管理に用いる.create table 文でテーブル iris を定義し,各列にデータ型を指定する.id 列には主キー制約(primary key)を設定する.トリプルクォート(""" … """)は複数行の文字列を表す.接続オブジェクトの execute メソッドでSQL文を実行する.

import sqlite3
conn = sqlite3.connect('hoge.sqlite')
sql = """
create table iris (
  id integer     primary key,
  sepal_length   real,
  sepal_width    real,
  petal_length   real,
  petal_width    real,
  species        text );
"""
conn.execute(sql)

④ CSVファイルの読み込みとテーブルへのデータ挿入

pandasの pd.read_csv(ファイル名, header=0) でCSVファイルを読み込む(header=0 は先頭行を列名として扱う指定).本演習で使用するCSVファイルにはヘッダー行があるため header=0 を指定する.このCSVファイルには id 列が含まれていないため,挿入時にはDataFrameのインデックス(0始まりの行番号)に1を加えた値を id として使用する.

x.iterrows() は,DataFrame x の各行を(行番号, 行データ)の組として返す.SQL文中の「?」はプレースホルダーであり,execute の第2引数のタプルの値で順に置き換えられる.insert into iris values (?, ?, ?, ?, ?, ?) は,テーブルに1行挿入するSQL文である.プレースホルダー ? の数(6個)と,テーブルの列数(6列)および execute の第2引数のタプルの要素数(6個)は一致させる.最後に conn.commit() を実行し,挿入したデータをデータベースに確定(コミット)する.conn.commit() を実行しない場合,挿入したデータは保存されない.

import pandas as pd
x = pd.read_csv('iris.csv', header=0)
for index, r in x.iterrows():
    sql = "insert into iris values (?, ?, ?, ?, ?, ?)"
    conn.execute(sql, (index + 1, r['sepal_length'], r['sepal_width'],
                       r['petal_length'], r['petal_width'], r['species']))
conn.commit()

⑤ テーブルの全データの読み出し

select * from iris は,iris テーブルの全行・全列を取得するSQL問い合わせである.fetchall() は問い合わせ結果の全行をリストで返し,各行はタプルとして表現される.

result = conn.execute("select * from iris").fetchall()
print(result)

⑥ 集約関数による合計・平均の取得

SUM()(合計値)と AVG()(平均値)はSQLの集約関数である.以下の例では sepal_length(がく片の長さ)を対象としている.sepal_widthpetal_length など他の数値属性に置き換えることもできる.集約関数の対象は数値型の属性に限定する(species のような文字列型の属性に対して SUM()AVG() を適用しても意味のある結果は得られない).

result = conn.execute("select sum(sepal_length), avg(sepal_length) from iris").fetchall()
print(result)

⑦ 接続を閉じる

データベース操作の終了後は conn.close() で接続を閉じる.

conn.close()

⑧ データベースファイルの確認

スクリプトの実行後,手順①で確認したカレントディレクトリに,データベースファイル hoge.sqlite が生成されていることを確認する.以下のPythonコードはWindows および Google Colab のいずれでも動作する.

import os
print(os.path.exists('hoge.sqlite'), os.path.getsize('hoge.sqlite'))

ヒント

考察ポイント