メモ書き:sqlite3

もしかしてsqlite3について書いてないのでは?ってなったのでメモ書きを。
今回は日付情報込みでデータベースを作りながらメモを書く。

前回、エミィに実装したBeTSCAE.dbの話はここにはありません。というかこの記憶貯蔵庫にはなさそうです。何のための記憶貯蔵庫なのですか?

セットアップ

def SetUp():
    import sqlite3
    import datetime
    
    dbname = r'                      '
    conn = sqlite3.connect(dbname, isolation_level=None, detect_types = sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
    sqlite3.dbapi2.converters['DATETIME'] = sqlite3.dbapi2.converters['TIMESTAMP']
    
    cursor = conn.cursor() 

    sql = "CREATE TABLE IF NOT EXISTS main(ID INTEGER PRIMARY KEY AUTOINCREMENT, Registered datetime, price)"
    cursor.execute(sql)
    conn.commit()

    sql = "CREATE TABLE IF NOT EXISTS F_30(ID INTEGER PRIMARY KEY AUTOINCREMENT, Registered DATETIME, PRICE INTEGER)"
    cursor.execute(sql)
    conn.commit()
    
    conn.close()

解説のつもり
1つめのSQL
「もしmainって名前のテーブルがなかったら作りなさい。」
「主キーはIDで数値、そして(指定がなければ)対象のカラムに格納されている最大の値に1を加えた値にしなさい。」
↑この時、データベースに何も入っていない場合、1から始まる。
「次はRegisteredでDATETIME。このDATETIMEはまあ上でなんやかんややってるから……うん……*1
「もう1個はPRICE。これは数値。」

SELECT

def read_30():
    import sqlite3
    dbname = r'                      '
    result = []
    
    conn = sqlite3.connect(dbname, isolation_level=None, detect_types = sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
    sqlite3.dbapi2.converters['DATETIME'] = sqlite3.dbapi2.converters['TIMESTAMP']
    cursor = conn.cursor() 
    sql = "SELECT PRICE FROM F_30 WHERE ID = (SELECT MAX(ID) FROM F_30)"
    for row in cursor.execute(sql):
        result.append(row)
    conn.close()
    
    return result[0][0]

何をやりたかったかの解説
テーブル「F_30」の中にあるもっとも新しいデータ*2のPRICEのキーを取得したかった。WHERE ID = (SELECT MAX(ID) FROM F_30)とすることで、IDが最も大きい行を見ることができる。SQL自信ないのよね。
なお、result[0][0]になっているのは、そのままresultで取得すると[(2855,)]のような形になるため。もうちょっといい方法ないかなぁ……?

Nullについて

= 演算子を使ってカラムの値を null と比較しても正しい結果が返ってこない。

少しだけデータを見たい

具体例

from contextlib import closing
from random import choice
import sqlite3
import SFamBasic as SFB
l =[]
dbname = ""
with closing(sqlite3.connect(dbname)) as connection:
    cursor = connection.cursor()
    sql = "SELECT M0,M1,M2,M3,M4,M5,M6 FROM MPD WHERE M0 = 1 LIMIT 10"
    for row in cursor.execute(sql):
        l.append(row)

print(l)

INSERT

def write(m,ns):
    from contextlib import closing
    import sqlite3
    import SFamBasic as SFB
    dbname = r'                       '
    now = SFB.now()
    
    conn = sqlite3.connect(dbname, isolation_level=None, detect_types = sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
    sqlite3.dbapi2.converters['DATETIME'] = sqlite3.dbapi2.converters['TIMESTAMP']
    cursor = conn.cursor() 
    sql1 = "INSERT INTO main (Registered, PRICE) values (?, ?)"
    sql2 = "INSERT INTO F_30 (Registered, PRICE) values (?, ?)"
    
    try:
        cursor.execute(sql1, (now,m))
        conn.commit()
    except Exception as e:
        print("Error in write() SQL1 : {}".format(e))
        print()
        
    try:
        cursor.execute(sql2, (now,ns))
        conn.commit()
    except Exception as e:
        print("Error in write() SQL2 : {}".format(e))
        print()
    conn.close()

補足

もしこれを読んでいる私がすべてを忘れた場合、これの元々のコードはAmesiorineではないうちの子の一部となっているはずです。探してください。271108として公開するにあたって雑にこのブログ記事編集画面で若干コードをいじりました。それに伴い、このままでは動かない可能性があります。

Incorrect number of bindings supplied. The current statement uses 1, [N>1] supplied.

executeの第2引数はタプルにしないといけません。

#ダメな例
db.execute('select * from users where name = ?', ('yamada'))
#良い例
db.execute('select * from users where name = ?', ('yamada',))

参考元サイトからの引用
※後で実際に私の手元で使ったものに似たカタチに差し替える
特に、SQLで扱う者が1列の場合やらかしやすいので注意。

InterfaceError: Error binding parameter 1 - probably unsupported type.

SQLに入れた変数のtypeがおかしいときに出るエラー。例えばstrで入れるところがtupleになってたりlistになってたりtupleになってたりtupleになってたりtupleになってたりtupleになってたりしてないか確認することだいたいtupleになってるんじゃないの?

IntegrityError

ユニーク制約エラー。ユニークなキーに同じ値を入力しようとしてる時に出るエラーのはず。

*1:※この時点で分かっていません。connectして、そのあとコンバーターを呼び出してるところでなんかやってる。

*2:※正確には最もIDの大きなデータ