Python Sqlite3:INSERT INTO table VALUE(这里是字典)

2024-03-29 12:28:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我想用字典把值插入到表中,我该怎么做?

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

Tags: totextexecutedbiftitletypeconnect
3条回答

有一个使用字典的解决方案。首先,sql语句

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

不会起作用,因为它假设您按照abarnert声明的CREATE TABLE语句中定义的顺序引用所有列。(见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)

如果试图使用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注入攻击,但也失去了在DB引擎中更快的编译、更好的缓存等不太重要的东西。

最好是退后一步,从更高的层次来看待这个问题。例如,也许您并不真正想要一个静态的属性列表,而是一个名称值MediaProperties表?或者,或者,您可能需要某种基于文档的存储(无论是高性能的nosql系统,还是存储在shelve中的一堆JSON或YAML对象)?


使用named placeholders的替代方法:

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

您可以使用named parameters

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的任何位置附近以python形式保存它们可能更明智。

相关问题 更多 >