【发布时间】:2010-10-06 22:18:21
【问题描述】:
将 python 中的列表作为二进制数据(即 BLOB 单元)转储到 sqlite3 DB 中的最优雅的方法是什么?
data = [ 0, 1, 2, 3, 4, 5 ]
# now write this to db as binary data
# 0000 0000
# 0000 0001
# ...
# 0000 0101
【问题讨论】:
将 python 中的列表作为二进制数据(即 BLOB 单元)转储到 sqlite3 DB 中的最优雅的方法是什么?
data = [ 0, 1, 2, 3, 4, 5 ]
# now write this to db as binary data
# 0000 0000
# 0000 0001
# ...
# 0000 0101
【问题讨论】:
Brian 的解决方案似乎符合您的需求,但请记住,使用该方法您只需将数据存储为字符串。
如果您想将原始二进制数据存储到数据库中(这样它不会占用太多空间),请将您的数据转换为 Binary sqlite 对象,然后将其添加到您的数据库中.
query = u'''insert into testtable VALUES(?)'''
b = sqlite3.Binary(some_binarydata)
cur.execute(query,(b,))
con.commit()
(由于某种原因,python 文档中似乎没有记录)
以下是关于 sqlite BLOB 数据限制的一些说明:
【讨论】:
假设您希望将其视为 8 位无符号值序列,请使用 array 模块。
a = array.array('B', data)
>>> a.tostring()
'\x00\x01\x02\x03\x04\x05'
如果您想将数据视为不同的类型,请使用与'B' 不同的类型代码。例如。 'b' 表示有符号字节序列,'i' 表示有符号整数。
【讨论】:
我有同样的问题,我正在考虑用另一种方式解决这个问题。
我认为pickle 模块正是为这样的事情完成的(python 对象的序列化)
示例(此示例用于转储到文件...但我认为它很容易用于数据库存储)
保存:
# Save a dictionary into a pickle file.
import pickle
favorite_color = { "lion": "yellow", "kitty": "red" }
pickle.dump( favorite_color, open( "save.p", "w" ) )
加载中:
# Load the dictionary back from the pickle file.
import pickle
favorite_color = pickle.load( open( "save.p" ) )
恕我直言,我认为这种方式更优雅、更安全(适用于任何 python 对象)。
那是我的 2 美分
更新: After doing a bit of search on my idea,他们在我的解决方案中显示了一些陷阱(我无法在该字段上进行 sql 搜索)。但我仍然认为这是一个不错的解决方案(如果您不需要搜索该字段。
【讨论】:
pickle 模块不安全并且可能不正确。通常最好使用 JSON 等更安全、更标准化的序列化协议。
在 SourceForge 上查看这个涵盖任意 Python 对象(包括列表、元组、字典等)的通用解决方案:
y_serial.py 模块 :: 使用 SQLite 存储 Python 对象
“序列化 + 持久化 :: 在几行代码中,将 Python 对象压缩并注释为 SQLite;然后稍后通过关键字按时间顺序检索它们,无需任何 SQL。数据库存储无模式数据的最有用的“标准”模块。”
【讨论】:
可以将对象数据存储为 pickle dump、jason 等,但也可以对它们进行索引、限制它们并运行使用这些索引的选择查询。这是元组的示例,可以轻松应用于任何其他 python 类。所有需要的都在 python sqlite3 文档中进行了解释(有人已经发布了链接)。无论如何,所有这些都放在以下示例中:
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))
#########################
# 1) Using declared types
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)")
cur.execute("select name, type from sqlite_master") # where type = 'table'")
print(cur.fetchall())
p = (1,2,3)
p1 = (1,2)
cur.execute("insert into test(p) values (?)", (p,))
cur.execute("insert into test(p) values (?)", (p1,))
cur.execute("insert into test(p) values (?)", ((10, 1),))
cur.execute("insert into test(p) values (?)", (tuple((9, 33)) ,))
cur.execute("insert into test(p) values (?)", (((9, 5), 33) ,))
try:
cur.execute("insert into test(p) values (?)", (tuple((9, 33)) ,))
except Exception as e:
print e
cur.execute("select p from test order by p")
print "\nwith declared types and default collate on column:"
for raw in cur:
print raw
cur.execute("select p from test order by p collate cmptuple")
print "\nwith declared types collate:"
for raw in cur:
print raw
con.create_function('pycmp', 2, cmp)
print "\nselect grater than using cmp function:"
cur.execute("select p from test where pycmp(p,?) >= 0", ((10, ),) )
for raw in cur:
print raw
cur.execute("select p from test where pycmp(p,?) >= 0", ((3,)))
for raw in cur:
print raw
print "\nselect grater than using collate:"
cur.execute("select p from test where p > ?", ((10,),) )
for raw in cur:
print raw
cur.execute("explain query plan select p from test where p > ?", ((3,)))
for raw in cur:
print raw
cur.close()
con.close()
【讨论】: