【Python】SQLiteでSQLエラーが発生する
SQLiteのプレースホルダー関連でエラーが発生するので解決砲を記載。ハマる人はハマるのではと思ったり。
なお、下記のソースはそのままでは動かないので適宜改変してください。
その1 ''で囲んでいる
ソース
sql = "SELECT NAME FROM MEMBERS WHERE NAME='?'" #<<<<<<これ name = "testname" try : #SQL実行 conn = sqlite3.connect("your db path.db") cur = conn.cursor() cur.execute(sql,(name, )) cur.close() conn.close() except: print(traceback.format_exc()) return DBResult.SQL_ERROR
結果
Traceback (most recent call last): sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 0, and there are 1 supplied.
原因
?を''で囲んだせいで、?
が文字列として認識されてしまっているようです。
よって、プレースホルダ(?)が0個なのに、値(name)を一個プレスホルダに入れようとしていてエラーになっています。
SQLをかじった人なら、SQL内で文字列比較する際には''囲みをすることを把握しているかと思います。 それにより引き起こされるミスですね。
解決策
下記のようにする
sql = "SELECT NAME FROM MEMBERS WHERE NAME=?"
その2 タプルで渡していない
ソース
sql = "INSERT INTO MEMBERS (NAME, GROUP) VALUES (?, ?)" values = ["testname", "A"] #<<<<<<これ try : #SQL実行 conn = sqlite3.connect("your db path.db") cur = conn.cursor() cur.execute(sql, values) #<<<<<<これ cur.close() conn.close() except: print(traceback.format_exc())
エラー
sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 1, and there are 2 supplied.
原因
execute()
の引数はタプル、executemany()
の引数はタプルのリストとなります。
実際の内部処理はよくわかりませんが、プレースホルダ(?)が2に対して、引数がリストでまとめて1つ、
と判断されているのだと思います。
上記のエラーでとりあえずググれば出てくる、有名な話ですね。
解決策
タプルに変換すればいいです
values = ("testname", "A") #タプルにしてあげる values = ("testname",) #要素が一つの場合は、末尾カンマも忘れずに #executemanyを使用する場合、タプルのリストに変換してあげる value_list = ["testname1","testname2","testname3"] tuple_list = [] for name in value_list: tuple_list.append((name,))
その3 executemanyをselectで使用している
ソース
sql = "SELECT NAME FROM MEMBERS WHERE NAME=?" name_list = ["aaa","bbb","ccc"] tuple_list = [] for name in name_list: name_list.append((name,)) #引数がlist[tuple]でないと受け付けないため、変換する try : #SQL実行 conn = sqlite3.connect("your db path.db") cur = conn.cursor() cur.executemany(sql, tuple_list) cur.close() conn.close() except: print(traceback.format_exc())
エラー
sqlite3.ProgrammingError: executemany() can only execute DML statements.
原因
executemanyはDML文でしか使用できません。
DML文とは、表の値を操作したり、削除したりと、「表に変更を与えるようなSQL文」です。
最後にcommit()
が必要な文ですね。
SELECT
は読み取るだけなので、表に変化は与えません。
なのでexecutemanyが使用できないみたいです。
解決策
条件文を駆使して、SQLの構文を用いてまとめて取得しましょう。 下記はIN文での例です
name_list = ["aaa","bbb","ccc"] sql = "SELECT NAME FROM MEMBERS WHERE NAME IN (" + ",".join(name_list) + ")" try : #SQL実行 conn = sqlite3.connect("your db path.db") cur = conn.cursor() cur.execute(sql) cur.close() conn.close() except: print(traceback.format_exc())
もしくはSQLを都度発行する方法もあります。 パフォーマンス的にはあまりよくないのかもしれませんが・・・
name_list = ["aaa","bbb","ccc"] try : sql = "SELECT NAME, GROUP FROM MEMBER WHERE NAME = ?" conn = sqlite3.connect("your db path.db") cur = conn.cursor() for name in name_list: cur.execute(sql, (name,)) records = cur.fetchall() print(records) cur.close() conn.close() except: print(sql) print(traceback.format_exc()) return DBResult.SQL_ERROR
まとめ
最近SQL全然使ってないのでハマった。