SQLiteでテーブル名を変数にしようと思ったらドはまりした話


 前回の記事で、SQLiteに接続し、データを投稿することに成功した。だが、後日振り返って「テーブル名を変数にしてクラス作れば今後の開発も楽じゃね?」などと思い、実際やってみたら思った以上に苦戦した履歴。

ドはまりしたところ

まず、Pythonで次のようなモジュールを作った。

import sqlite3 as sql

dbpath="H:\Data\yieldcurve.db"
conn=sql.connect(dbpath)

cur=conn.cursor()
name='FFRate'
cur.execute("CREATE TABLE IF NOT EXISTS %s" % name)
conn.commit()
cur=conn.cursor()
responce
sqlite3.OperationalError: near "FFRate": syntax error

動かない。?を使っても同じ

()

cur.execute("CREATE TABLE IF NOT EXISTS ?" ,name)

()
responce
    cur.execute("CREATE TABLE IF NOT EXISTS ?" ,name)
sqlite3.OperationalError: near "?": syntax error

解決策

いろいろと試したが、このサイトにあったやり方を応用したら動いた。

cur.execute("CREATE TABLE IF NOT EXISTS table_info('%s')" % name)

'%s'を?に置き換えるとうまくいかなくなる。

cur.execute("CREATE TABLE IF NOT EXISTS table_info(?)" , name)
responce
   cur.execute("CREATE TABLE IF NOT EXISTS table_info(?)" , name)
sqlite3.OperationalError: near "?": syntax error

まあ・・・とりあえず動いたし良いかな。
今度は、何度動かしても結果を同じにするため、テーブルをDROPする項目を書き加えて見たところ、動かなくなった。

import sqlite3 as sql
dbpath="H:\Data\yieldcurve.db"
conn=sql.connect(dbpath)

cur=conn.cursor()
name='FFRate'

cur.execute("DROP TABLE IF EXISTS table_info('%s')" % name)
cur.execute("CREATE TABLE IF NOT EXISTS table_info(?)" , name)

conn.commit()
cur=conn.cursor()
responce
    cur.execute("DROP TABLE IF EXISTS table_info('%s')" % name)
sqlite3.OperationalError: near "(": syntax error

もしかして?と思い、table_infoを消去したら、動くようになった。

cur.execute("DROP TABLE IF EXISTS %s" % name)
cur.execute("CREATE TABLE IF NOT EXISTS table_info('%s')" % name)

この違いは何なのだろうか・・・とりあえず先に進めることにしよう。
cur.executeが2行も続くのは鬱陶しいと思い、まとめてみたところ、「命令は一つにしろよ」と怒られた。

cur.execute("""
    DROP TABLE IF EXISTS %s;
    CREATE TABLE IF NOT EXISTS table_info('%s')""" 
    % (name,name,))

教科書をよく見たら、cur.executescriptと書かなければならないようだ。

cur.executescript("""
    DROP TABLE IF EXISTS %s;
    CREATE TABLE IF NOT EXISTS table_info('%s')""" 
    % (name,name,))

これで一応は動作する。

まとめ

とりあえず、テーブル名を変数としてSQLite動かすことができた。しかし、SQLite3の公式ドキュメントをもう一度読むと、どうもこの書き方は危険らしい。(なぜ危険なのかよくわからないが)
また、なぜDROPとCREATEで書き方が異なるのか、疑問が残る。
何れにせよ今後改良していきたいところだが、今回はこのまま続行していうと思う。

参考文献

・Pythonによるスクレイピング&機械学習
PythonでSQLite - カラムの新規追加
・解決策が書いてあるっぽいけどクソ雑魚過ぎて意味がわからなかったページ[Variable table name in sqlite]