Подтвердить что ты не робот

Python Sqlite3: INSERT INTO table VALUE (словарь идет здесь)

Я хотел бы использовать словарь для вставки значений в таблицу, как бы я это сделал?

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
4b9b3361

Ответ 1

Если вы пытаетесь использовать dict для указания имен столбцов и значений, вы не можете этого сделать, по крайней мере, не напрямую.

Это действительно присуще SQL. Если вы не укажете список имен столбцов, вы должны указать их в порядке CREATE TABLE, который вы не можете сделать с помощью dict, потому что dict не имеет порядка. Если вы действительно хотели, конечно, вы могли бы использовать collections.OrderedDict, убедитесь, что он в правильном порядке, а затем просто пройдите values.values(). Но в этот момент, почему бы просто не иметь list (или tuple) в первую очередь? Если вы абсолютно уверены, что у вас есть все значения в правильном порядке, и вы хотите ссылаться на них по порядку, а не по имени, то у вас есть list, а не dict.

И нет способа привязать имена столбцов (или имена таблиц и т.д.) в SQL, просто значения.

Вы можете, конечно, генерировать инструкцию SQL динамически. Например:

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

Однако это почти всегда плохая идея. Это действительно не намного лучше, чем генерация и exec динамический код Python. И вы только что потеряли все преимущества использования заполнителей в первую очередь - прежде всего защиту от атак SQL-инъекций, а также менее важные вещи, такие как более быстрая компиляция, лучшее кэширование и т.д. Внутри механизма БД.

Вероятно, лучше отступить и посмотреть на эту проблему с более высокого уровня. Например, может быть, вам действительно не нужен статический список свойств, а таблица имен MediaProperties? Или, альтернативно, возможно, вам нужно какое-то хранилище на основе документов (будь то мощная система nosql или просто куча объектов JSON или YAML, хранящихся в 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()

Ответ 2

Существует решение для использования словарей. Во-первых, sql-statement

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

не работает, так как предполагает, что вы ссылаетесь на все столбцы в том порядке, в котором они определены в инструкции CREATE TABLE, как указано в abarnert. (См. SQLite INSERT.)

Как только вы исправили его, указав столбцы, вы можете использовать именованные заполнители для вставки данных. Преимущество этого заключается в том, что безопасно ускользает от ключевых символов, поэтому вам не нужно беспокоиться. Из Python sqlite-документации:

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)

Ответ 3

Вы можете использовать именованные параметры:

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

Это все еще зависит от порядка столбцов в выражении INSERT (те : используются только как ключи в values dict), но по крайней мере у него не получается заказать значения на стороне python, плюс вы можете иметь другие вещи в values, которые здесь игнорируются; если вы тянете то, что в дикторе, чтобы хранить его в нескольких таблицах, это может быть полезно.

Если вы все же хотите избежать дублирования имен, вы можете извлечь их из объекта результата sqlite3.Row или из cur.description после выполнения фиктивного запроса; может быть разумнее держать их в форме питона около того, где вы делаете свой CREATE TABLE.

Ответ 4

Вот более общий способ с преимуществом побега:

# One way. If keys can be corrupted don't use.
sql = 'INSERT INTO demo ({}) VALUES ({})'.format(
            ','.join(my_dict.keys()),
            ','.join(['?']*len(my_dict)))

# Another, better way. Hardcoded w/ your keys.
sql = 'INSERT INTO demo ({}) VALUES ({})'.format(
            ','.join(my_keys),
            ','.join(['?']*len(my_dict)))

cur.execute(sql, tuple(my_dict.values()))

Ответ 5

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 где-нибудь.

Ответ 6

У меня была аналогичная проблема, поэтому я сначала создал строку, а затем передал эту строку для выполнения команды. Выполнение занимает больше времени, но для меня идеально подходит. Просто работа вокруг:

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)

Выполняя эту задачу, я убедился, что если мой dict (record_tab) не содержит отдельного поля, то можно сделать ошибку script и исключить правильное сопоставление, поэтому я использовал словарь в первую очередь.

Ответ 7

У меня была аналогичная проблема, и я получил нечто совсем не похожее на следующее (Примечание - это код OP с битами, измененными так, чтобы он работал так, как они просили) -

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)

Ответ 8

Очень поздно, но решил, что добавлю свой ответ. Не эксперт, но кое-что, что я нашел, работает.

Существуют проблемы с сохранением порядка при использовании словаря, о которых заявили другие пользователи, но вы можете сделать следующее:

# We're going to use a list of dictionaries, since that what I'm having to use in my problem
input_list = [{'a' : 1 , 'b' : 2 , 'c' : 3} , {'a' : 14 , 'b' : '' , 'c' : 43}]
for i in input_list:
    # I recommend putting this inside a function, this way if this 
    # Evaluates to None at the end of the loop, you can exit without doing an insert
    if i :
        input_dict = i 
    else:
        input_dict = None
        continue
# I am noting here that in my case, I know all columns will exist.
# If you're not sure, you'll have to get all possible columns first.

keylist = list(input_dict.keys())
vallist = list(input_dict.values())

query = 'INSERT INTO example (' +','.join( ['[' + i + ']' for i in keylist]) + ') VALUES (' + ','.join(['?' for i in vallist]) + ')'

items_to_insert = list(tuple(x.get(i , '') for i in keylist) for x in input_list)
# Making sure to preserve insert order. 

conn = sqlite3.connect(':memory:')
cur = conn.cursor()
cur.executemany(query , items_to_insert)
conn.commit()