首页 > 解决方案 > 如何通过 SQLAlchemy 在 python 中的 sqlite3 db 中部分覆盖 blob?

问题描述

我有一个包含二进制表示的 blob 列的数据库,如下所示

DB Browser 显示的 blob

我感兴趣的值在标记中被编码为 little endian unsigned long long (8 字节) 值。像这样读取这个值可以正常工作

p = session.query(Properties).filter((Properties.object_id==1817012) & (Properties.name.like("%OwnerUniqueID"))).one()
id = unpack("<Q", p.value[-8:])[0]

上面例子中的 id 是 1657266。现在我想做的是相反的。我有行对象 p,我有一个十进制格式的数字(出于测试目的使用相同的 1657266),我想以小端格式将该数字写入相同的 8 个字节。我一直在尝试通过 SQL 语句这样做

UPDATE properties SET value = (SELECT substr(value, 1, length(value)-8) || x'b249190000000000' FROM properties WHERE object_id=1817012 AND name LIKE '%OwnerUniqueID%') WHERE object_id=1817012 AND name LIKE '%OwnerUniqueID%'

但是当我这样做时,我就无法再阅读它了。至少不使用 SQLAlchemy。当我尝试与上面相同的代码时,我收到错误消息Could not decode to UTF-8 column 'properties_value' with text '☻',因此看起来它是以不同的格式编写的。有趣的是,在 DB Browser 中使用普通的 select 语句仍然可以正常工作,并且 blob 仍然与上面的屏幕截图完全相同。现在理想情况下,我希望能够使用 SQLAlchemy ORM 仅写入这 8 个字节,但如果需要的话,我会满足于原始 SQL 语句。

标签: pythonsqlalchemyblob

解决方案


通过基本上扭转我过去阅读它的过程,我设法让它与 SQLAlchemy 一起工作。事后看来,使用 + 连接和 [:-8] 分割正确的部分似乎很明显。

p = session.query(Properties).filter((Properties.object_id==1817012) & (Properties.name.like("%OwnerUniqueID"))).one()
p.value = p.value[:-8] + pack("<Q", 1657266)

通过为 SQLAlchemy 打开 ECHO,我得到了以下原始 SQL 语句:

UPDATE properties SET value=? WHERE properties.object_id = ? AND properties.name = ?
(<memory at 0x000001B93A266A00>, 1817012, 'BP_ThrallComponent_C.OwnerUniqueID')

如果你想手动做同样的事情,这不是特别有用。

值得注意的是,我的问题中的原始 SQL 语句不仅适用于使用 DB 浏览器阅读它,而且适用于使用相关数据库的游戏客户端。只有 SQLAlchemy 似乎有问题,试图将其解码为 UTF-8。


推荐阅读