在Python中将元组保存为Sqlite3的blob数据类型

0 投票
3 回答
4512 浏览
提问于 2025-04-16 13:26

我在Python里有一个字典。这个字典的键是包含不同大小的元组,里面有一些unicode字符,而值则是一个单独的整数。我想把这个字典放进SQLite数据库,创建一个有两列的表。

第一列用来存放键,第二列用来存放对应的整数值。为什么我想这么做呢?因为我的字典非常大,我用过cPickle,甚至把协议设置成2,但文件的大小还是很大,保存和加载这个文件都花了很多时间。所以我决定把它存到数据库里。这个字典在程序开始时只加载一次到内存里,所以之后就没有额外的操作了。

现在的问题是,我想把元组保存为元组(而不是字符串),这样每次我把表加载到内存时,就可以立即构建我的字典,毫无问题。有没有人知道我该怎么做?

3 个回答

-1

我觉得在你的表格里创建三列会更好,分别是 key1、key2 和 value。

如果你想把键保存为一个元组(就是一组数据),你还是可以使用 pickle,但只对键进行处理。然后你可以把它保存为 blob(大对象)。

>>> pickle.dumps((u"\u20AC",u"\u20AC"))
'(V\\u20ac\np0\ng0\ntp1\n.'
>>> pickle.loads(_)
(u'\u20ac', u'\u20ac')
>>>
2

可以把元组存储到sqlite数据库里,并且可以在这些元组上创建索引。不过,这需要一些额外的代码来实现。至于在这种情况下,把元组存储到数据库里是否合适,这又是另一个问题(可能用两个键的解决方案会更合适)。

import sqlite3
import pickle

def adapt_tuple(tuple):
    return pickle.dumps(tuple)    

sqlite3.register_adapter(tuple, adapt_tuple)    #cannot use pickle.dumps directly because of inadequate argument signature 
sqlite3.register_converter("tuple", pickle.loads)

def collate_tuple(string1, string2):
    return cmp(pickle.loads(string1), pickle.loads(string2))

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)

con.create_collation("cmptuple", collate_tuple)

cur = con.cursor()
cur.execute("create table test(p tuple unique collate cmptuple) ")
cur.execute("create index tuple_collated_index on test(p collate cmptuple)")

#insert
p = (1,2,3)
p1 = (1,2)

cur.execute("insert into test(p) values (?)", (p,))
cur.execute("insert into test(p) values (?)", (p1,))

#ordered select
cur.execute("select p from test order by p collate cmptuple")
3

有几点需要说明。首先,SQLite不允许你直接存储Python的数据结构。其次,我猜你是想根据元组的键来查询值,所以你不想先把数据打包再解包,然后再在字典里查找键。

问题是,你不能用元组来查询,而且你也不能把元组里的每个元素拆分到不同的列,因为它们的大小是不一样的。如果你一定要用SQLite,那你基本上需要把元组里的字符连接起来,可能还要用一个不在元组值中的分隔符。然后把这个连接后的字符串当作键,存储到SQLite的一个主键列里。

def tuple2key(t, delimiter=u':'):
    return delimiter.join(t)

import sqlite3

conn = sqlite3.connect('/path/to/your/db')
cur = conn.cursor()

cur.execute('''create table tab (k text primary key, value integer)''')

# store the dict into a table
for k, v in my_dict.iteritems():
    cur.execute('''insert into tab values (?, ?)''', (tuple2key(k), v))

cur.commit()

# query the values
v = cur.execute(''' select value from tab where key = ? ''', tuple2key((u'a',u'b'))).fetchone()

撰写回答