Python Sqlite3: INSERT INTO table VALUE (el diccionario va aquí)

Me gustaría usar un diccionario para insertar valores en una tabla, ¿cómo haría esto?

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 

Si está intentando usar un dict para especificar los nombres de columna y los valores, no puede hacerlo, al menos no directamente.

Eso es realmente inherente a SQL. Si no especifica la lista de nombres de columna, debe especificarlos en el orden CREATE TABLE , lo que no puede hacer con un dict , porque un dict no tiene orden. Si realmente quisiera, por supuesto, podría usar una collections.OrderedDict ordenado, asegúrese de que esté en el orden correcto, y luego simplemente pase values.values() . Pero en ese punto, ¿por qué no tener una list (o tuple ) en primer lugar? Si está absolutamente seguro de que tiene todos los valores, en el orden correcto, y desea referirse a ellos por orden en lugar de por nombre, lo que tiene es una list , no un dict .

Y no hay forma de vincular nombres de columnas (o nombres de tablas, etc.) en SQL, solo valores.

Por supuesto, puede generar dinámicamente la instrucción SQL. Por ejemplo:

 columns = ', '.join(values.keys()) placeholders = ', '.join('?' * len(values)) sql = 'INSERT INTO Media ({}) VALUES ({})'.format(columns, placeholders) cur.execute(sql, values.values()) 

Sin embargo, esto es casi siempre una mala idea. Esto realmente no es mucho mejor que generar y exec código dynamic de Python. Y acaba de perder todos los beneficios de usar marcadores de posición en primer lugar: principalmente protección contra ataques de inyección de SQL, pero también cosas menos importantes como una comstackción más rápida, mejor almacenamiento en caché, etc., dentro del motor de base de datos.

Probablemente sea mejor dar un paso atrás y ver este problema desde un nivel superior. Por ejemplo, tal vez realmente no quería una lista estática de propiedades, sino una tabla de propiedades de nombre y valor. O, alternativamente, tal vez desee algún tipo de almacenamiento basado en documentos (ya sea un sistema nosql de alta potencia, o solo un grupo de objetos JSON o YAML almacenados en una shelve ).


Una alternativa utilizando marcadores de posición nombrados :

 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() 

Hay una solución para usar diccionarios. Primero, la sentencia sql

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

no funcionaría, ya que se supone que se está refiriendo a todas las columnas, en el orden en que están definidas en la CREATE TABLE , como abarnert declaró. (Ver SQLite INSERT .)

Una vez que lo haya arreglado especificando las columnas, puede usar marcadores de posición con nombre para insertar datos. La ventaja de esto es que se escapa de forma segura de los caracteres clave, por lo que no tiene que preocuparse. De la documentación sqlite de Python :

 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) 

Podrías usar parámetros nombrados :

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

Esto aún depende del orden de las columnas en la INSERT (esas : solo se usan como claves en los values dict), pero al menos evita tener que ordenar los valores en el lado de python, además, puede tener otras cosas en values que se ignoran aquí; Si está separando lo que está en el dictado para almacenarlo en varias tablas, eso puede ser útil.

Si aún desea evitar duplicar los nombres, puede extraerlos de un objeto de resultado sqlite3.Row , o de cur.description , después de hacer una consulta ficticia; puede ser más sensato mantenerlos en forma de python cerca de donde haga su CREATE TABLE .

 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)) 

Haz tu derecho a escapar.

Probablemente también necesites una llamada de commit en algún lugar.

Tenía un problema similar, así que primero creé una cadena y luego pasé esa cadena para ejecutar el comando. Lleva más tiempo ejecutarlo, pero el mapeo fue perfecto para mí. Sólo un trabajo alrededor de:

 create_string = "INSERT INTO datapath_rtg( Sr_no" for key in record_tab: create_string = create_string+ " ," + str(key) create_string = create_string+ ") VALUES("+ str(Sr_no) for key in record_tab: create_string = create_string+ " ," + str(record_tab[key]) create_string = create_string + ")" cursor.execute(create_string) 

Al hacer lo anterior, me aseguré de que si mi dict (record_tab) no contiene un campo en particular, la secuencia de comandos no arroje un error y se pueda realizar la asignación adecuada, por lo que usé el diccionario en primer lugar.

Estaba teniendo un problema similar y terminé con algo que no era totalmente diferente al siguiente (Nota: este es el código del OP con bits modificados para que funcione de la forma que solicitaron)

 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) # Added code. cur.execute('SELECT * FROM Media') colnames = cur.description list = [row[0] for row in cur.description] new_list = [values[i] for i in list if i in values.keys()] sql = "INSERT INTO Media VALUES ( NULL, " qmarks = ', '.join('?' * len(values)) sql += qmarks + ")" cur.execute(sql, new_list) #db.commit() #<-Might be important. cur.execute('SELECT * FROM Media') media = cur.fetchone() print (media)