41

ディクショナリを使用してテーブルに値を挿入したいのですが、どうすればよいですか?

import sqlite3

db = sqlite3.connect('local.db')
cur = db.cursor()

cur.execute('DROP TABLE IF EXISTS Media')

cur.execute('''CREATE TABLE IF NOT EXISTS Media(
                id INTEGER PRIMARY KEY, title TEXT, 
                type TEXT,  genre TEXT,
                onchapter INTEGER,  chapters INTEGER,
                status TEXT
                )''')


values = {'title':'jack', 'type':None, 'genre':'Action', 'onchapter':None,'chapters':6,'status':'Ongoing'}

#What would I Replace x with to allow a 
#dictionary to connect to the values? 
cur.execute('INSERT INTO Media VALUES (NULL, x)'), values)
cur.execute('SELECT * FROM Media')

meida = cur.fetchone()

print meida
4

9 に答える 9

46

a を使用して列名と値の両方を指定しようとしている場合dict、少なくとも直接的にはできません。

これは、SQL に固有のものです。列名のリストを指定しない場合は、それらを順番に指定する必要があります。a には順序がないため、これCREATE TABLEは a では実行できません。もちろん、本当にしたい場合は、 a を使用し、正しい順序であることを確認してから、 を渡すことができます。しかし、その時点で、そもそも(または) だけを使用しないのはなぜでしょうか? すべての値を正しい順序で取得したことが確実であり、それらを名前ではなく順序で参照したい場合、あなたが持っているのはではなくです。dictdictcollections.OrderedDictvalues.values()listtuplelistdict

また、SQL で列名 (またはテーブル名など) をバインドする方法はなく、値だけです。

もちろん、SQL ステートメントを動的に生成することもできます。例えば:

columns = ', '.join(values.keys())
placeholders = ', '.join('?' * len(values))
sql = 'INSERT INTO Media ({}) VALUES ({})'.format(columns, placeholders)
values = [int(x) if isinstance(x, bool) else x for x in values.values()]
cur.execute(sql, values)

ただし、これはほとんどの場合、悪い考えです。execこれは、動的な Python コードを生成して ing するよりもはるかに優れているわけではありません。そして、そもそもプレースホルダーを使用する利点をすべて失ってしまいました。主に SQL インジェクション攻撃からの保護だけでなく、DB エンジン内でのコンパイルの高速化、キャッシュの改善など、それほど重要ではありません。

一歩下がって、この問題をより高いレベルから見てみる方がよいでしょう。たとえば、実際にはプロパティの静的リストではなく、名前と値MediaPropertiesのテーブルが必要だったのではないでしょうか? あるいは、ある種のドキュメントベースのストレージが必要になるかもしれません (それが強力な nosql システムであろうと、 shelve.


名前付きプレースホルダーを使用する代替方法:

columns = ', '.join(my_dict.keys())
placeholders = ':'+', :'.join(my_dict.keys())
query = 'INSERT INTO my_table (%s) VALUES (%s)' % (columns, placeholders)
print query
cur.execute(query, my_dict)
con.commit()
于 2013-01-01T06:59:21.260 に答える
19

辞書を使用するための解決策があります。まず、SQL ステートメント

INSERT INTO Media VALUES (NULL, 'x');

CREATE TABLEabarnertが述べたように、ステートメントで定義されている順序ですべての列を参照していると想定しているため、機能しません。( SQLite INSERTを参照してください。)

列を指定して修正したら、名前付きプレースホルダーを使用してデータを挿入できます。これの利点は、キー文字を安全にエスケープできるため、心配する必要がないことです。Python sqlite-documentationから:

values = {
    'title':'jack', 'type':None, 'genre':'Action', 
    'onchapter':None,'chapters':6,'status':'Ongoing'
}
cur.execute(
    'INSERT INTO Media (id, title, type, onchapter, chapters, status)
     VALUES (:id, :title, :type, :onchapter, :chapters, :status);', 
    values
)
于 2013-05-22T17:41:22.067 に答える
12

名前付きパラメータを使用できます:

cur.execute('INSERT INTO Media VALUES (NULL, :title, :type, :genre, :onchapter, :chapters, :status)', values)

INSERTこれはまだステートメント内の列の順序に依存します(それら:valuesdict のキーとしてのみ使用されます) が、少なくとも Python 側で値を順序付けする必要がなくなります。さらに、valuesここでは無視される他のものを含めることができます。複数のテーブルに格納するために dict の内容を引き離している場合、それは便利です。

名前の重複を避けたい場合は、ダミー クエリを実行した後、sqlite3.Row結果オブジェクトまたは から名前を抽出できます。cur.descriptionあなたがあなたのCREATE TABLE.

于 2015-01-15T01:54:35.047 に答える
1
key_lst = ('status', 'title', 'chapters', 'onchapter', 'genre', 'type')
cur.execute('INSERT INTO Media (status,title,chapters,onchapter,genre,type) VALUES ' + 
            '(?,?,?,?,?,?);)',tuple(values[k] for k in key_lst))

正しくエスケープしてください。

commitまた、どこかに電話する必要があるかもしれません。

于 2013-01-01T07:00:37.970 に答える