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

如果您尝试使用 adict来指定列名和值,则不能这样做,至少不能直接这样做。

这确实是 SQL 固有的。如果您不指定列名列表,则必须按CREATE TABLE顺序指定它们 - 您不能使用 a 执行此操作dict,因为 adict没有顺序。如果你真的想要,当然,你可以使用 a collections.OrderedDict,确保它的顺序正确,然后就通过values.values()。但是到那时,为什么不首先有一个list(或tuple)呢?如果您绝对确定您已经以正确的顺序获得了所有值,并且您想按顺序而不是按名称引用它们,那么您所拥有的是 a list,而不是 a dict

并且没有办法在 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)

然而,这几乎总是一个坏主意。这实际上并不比生成和execing 动态 Python 代码好多少。而且您一开始就失去了使用占位符的所有好处——主要是保护免受 SQL 注入攻击,但也失去了数据库引擎中不太重要的东西,例如更快的编译、更好的缓存等。

最好退后一步,从更高的层面看待这个问题。例如,也许您并不真正想要一个静态的属性列表,而是一个名称-值MediaProperties表?或者,或者,也许您想要某种基于文档的存储(无论是高性能的 nosql 系统,还是只是存储在 a 中的一堆 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()
于 2013-01-01T06:59:21.260 回答
19

有一个使用字典的解决方案。一、SQL语句

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

将不起作用,因为它假定您按照它们在CREATE TABLE语句中定义的顺序引用所有列,如 abarnert 所述。(参见SQLite 插入。)

通过指定列修复它后,您可以使用命名占位符插入数据。这样做的好处是可以安全地转义关键字符,因此您不必担心。来自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
)
于 2013-05-22T17:41:22.067 回答
12

您可以使用命名参数

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

这仍然取决于INSERT语句中的列顺序(那些:仅用作values字典中的键),但它至少不必在 python 端对值进行排序,而且您可以在values此处忽略其他内容;如果您将 dict 中的内容分开以将其存储在多个表中,那将很有用。

如果您仍想避免重复名称,则可以在执行虚拟查询后从sqlite3.Row结果对象或从中提取它们;cur.description将它们以 python 形式保存在您进行CREATE TABLE.

于 2015-01-15T01:54:35.047 回答
2

这是一种更通用的方式,具有转义的好处:

# 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()))
于 2019-06-06T16:52:46.673 回答
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 回答
1

超级晚了,但我想我会添加我自己的答案。不是专家,但我发现有些东西有效。

使用字典时保留顺序存在问题,其他用户已说明,但您可以执行以下操作:

# We're going to use a list of dictionaries, since that's 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()
于 2019-09-10T14:45:34.050 回答
1
dictionary = {'id':123, 'name': 'Abc', 'address':'xyz'}    
query = "insert into table_name " + str(tuple(dictionary.keys())) + " values" + str(tuple(dictionary.values())) + ";"
cursor.execute(query)

查询变成

insert into table_name ('id', 'name', 'address') values(123, 'Abc', 'xyz');
于 2020-05-06T12:01:47.960 回答
0

我遇到了类似的问题,所以我先创建了一个字符串,然后将该字符串传递给执行命令。执行确实需要更长的时间,但映射对我来说是完美的。只是一个解决方法:

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) 不包含特定字段,则脚本不会抛出错误并且可以完成正确的映射,这就是我首先使用字典的原因。

于 2017-01-18T08:52:37.087 回答
0

我遇到了类似的问题,最终得到的结果与以下内容并不完全不同(注意 - 这是 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)
于 2018-02-19T00:41:16.627 回答