今さらPython3 (56) - RDBMS

第8章のリレーショナルデータベースのところです。

入門 Python 3

入門 Python 3

PythonRDBMSをつなぐ

と言えば、かつてFilemakerPython(2.7)を繋げてゴニョゴニョしたことがありました。その時の様子はこの記事から5回シリーズぐらいでやったはず。

deutschina.hatenablog.com

RDBMSとかSQLとは?的な問いについては、他に当たってもらうとして、この中ではPythonの中で使うというところを見る。

legacy.python.org

このモジュールを直接使うというより、使用しているDBに依存したものが出ているはず。

SQLite

やっぱり最初はこれでしたか。昔iPhoneアプリを作ったときにも、最初はこれを使っていたね。

>>> import sqlite3
>>> conn = sqlite3.connect('enterprise.db')
>>> curs = conn.cursor()
>>> curs.execute('''CREATE TABLE zoo (critter VARCHAR(20) PRIMARY KEY, count INT, damages FLOAT)''')
<sqlite3.Cursor object at 0x101b82730>
>>> 

えっと、意味を確認。enterprise.dbというファイルに接続して、zooというテーブルを作りますと。テーブル内の項目は、critterという可変長文字列がプライマリキー項目、countという数字の項目、damagesという浮動小数点項目ですと。本の中には整数型と改訂あるけど、execute文を見る限りはFLOATで作っているので誤植だね。

f:id:deutschina:20151223175348p:plain

ファイルがない場合は作ってくれるというお手軽さ。

>>> curs.execute('INSERT INTO zoo VALUES("duck", 5, 0.0)')
<sqlite3.Cursor object at 0x101b82730>
>>> curs.execute('INSERT INTO zoo VALUES("bear", 2, 1000.0)')
<sqlite3.Cursor object at 0x101b82730>
>>> ins = 'INSERT INTO zoo (critter, count, damages) VALUES(?, ?, ?)'
>>> curs.execute(ins, ('weasel', 1, 2000.0))
<sqlite3.Cursor object at 0x101b82730>

書きっぷりは少し違うものの、エントリを3つINSERTしていますと。てか、SQLiteだとcommitいらないんだっけ?

>>> curs.execute('SELECT * FROM zoo')
<sqlite3.Cursor object at 0x101b82730>
>>> rows = curs.fetchall()
>>> print(rows)
[('duck', 5, 0.0), ('bear', 2, 1000.0), ('weasel', 1, 2000.0)]
>>> 

そんな疑問も、SELECTで中身を出してみれば解決。はい、ちゃんと3件登録されていましたね。ちなみに、タプルのリストとして出力されることも確認できたね。

>>> curs.execute('SELECT * FROM zoo ORDER BY count')
<sqlite3.Cursor object at 0x101b82730>
>>> rows = curs.fetchall()
>>> print(rows)
[('weasel', 1, 2000.0), ('bear', 2, 1000.0), ('duck', 5, 0.0)]
>>> 

countを昇順でソートしているパターン。最初、damageに目が行って、なんで降順なの?と思ってしまった。

>>> curs.execute('SELECT * FROM zoo ORDER BY count DESC')
<sqlite3.Cursor object at 0x101b82730>
>>> rows = curs.fetchall()
>>> print(rows)
[('duck', 5, 0.0), ('bear', 2, 1000.0), ('weasel', 1, 2000.0)]
>>> 

降順オプションはDESCをつけるのね。DESCENDINGかと思ってました。ちなみに、この本にも書いてあったけど、テーブルと項目名は小文字、それ以外のキーワードは大文字で書くようにしてます。(本は一部、fromって小文字で書いてあるところがあったけどね)

次は、damageが最大のモノを選択。これで良いのかなと思ったら、ちと失敗。

>>> curs.execute('SELECT MAX(damages) FROM zoo')
<sqlite3.Cursor object at 0x101b82730>
>>> rows = curs.fetchall()
>>> print(rows)
[(2000.0,)]

damageの金額だけ出てきちゃったので、ちゃんと本と同じようにやりましょう。

>>> curs.execute('''SELECT * FROM zoo WHERE damages = (SELECT MAX(damages) FROM zoo)''')
<sqlite3.Cursor object at 0x101b82730>
>>> rows = curs.fetchall()
>>> print(rows)
[('weasel', 1, 2000.0)]
>>> 

なるほどね。

>>> curs.close()
>>> conn.close()

後始末はお忘れなく。てか、withは使えないのかな?てか使えたような気がする。

>>> with conn.cursor() as curs:
...     curs.execute('SELECT * FROM zoo')
...     rows = curs.fetchall()
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: __exit__
>>> 

・・・ダメだったか。

MySQL, PostgreSQL

同じレッスンを繰り返してくれるのかなと思ったら、そうも行かないようで、ドライバの紹介で終わってますね。まずは、MySQLから。

github.com
MySQLConnector http://dev.mysql.com/doc/connector-python/en/
oursqlWelcome to oursql’s documentation! — oursql v0.9.2 documentation

3つ載っているけど、少し前に調べたときはMySQLConnectorがしばらく放置されている感じだったので、PyMySQLを入れたという経緯あり。

>>> import pymysql
>>>

うん。入ってる。あと書き忘れたけど、MariaDBでも問題なく使えます。

PostgreSQLの場合は、以下の2つが紹介されている。

initd.org
py-postgresql

日本語でググった限りだと、上の方が優勢っぽく見える。将来的にPostgreSQLを使うケースが出たら読み込んでみようかな。

(つづく)