在SQLite数据库中存储布尔值

7
在我的表结构中:
... disabled BOOLEAN, ...

连接数据库时:

db = sqlite3.connect(f, detect_types=sqlite3.PARSE_DECLTYPES)
sqlite3.register_converter("BOOLEAN", myfunc)

我这样插入一条记录:

INSERT INTO mytable (disabled, ...) VALUES (:disabled, ...)

参数字典中包含disabled: False。

当我读取该记录时,将调用myfunc函数来转换布尔类型:

def myfunc(x):
    print x, type(x)

结果: 0,<type 'str'>(当我想要False时当然会评估为True)
我希望将bool存储为1字节的INTEGER,当读取记录时,我只想将它们转换为Python bool(代码的其他部分需要bool而不是int)。 SQLite是将它们存储为字符串,还是在调用myfunc之前将它们转换为字符串?为什么?
附:我尝试使用sqlite3.register_adapter(bool, int),但没有成功。

我不知道为什么你得到了一个字符串,但是暂时将它们转换为整数然后再转换为布尔值应该是一个解决方法。 - pypat
2个回答

26

你想在两个方向上使用 register_adapterregister_converter 的组合:

sqlite3.register_adapter(bool, int)
sqlite3.register_converter("BOOLEAN", lambda v: bool(int(v)))

SQLite使用动态类型系统,但对于自定义类型,它无法确定 0 是字符串还是整数,因此在此处返回的是一个字符串。

或者,可以使用:

sqlite3.register_converter("BOOLEAN", lambda v: v != '0')

相比于传统数据来说,这更加灵活和健壮,但也许您想要出现异常情况。

演示:

>>> import sqlite3
>>> db = sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES)
>>> sqlite3.register_adapter(bool, int)
>>> sqlite3.register_converter("BOOLEAN", lambda v: bool(int(v)))
>>> db.execute('CREATE TABLE foo (bar BOOLEAN)')
<sqlite3.Cursor object at 0x10a17a340>
>>> db.execute('INSERT INTO foo VALUES (?)', (True,))
<sqlite3.Cursor object at 0x10a17a3b0>
>>> db.execute('INSERT INTO foo VALUES (?)', (False,))
<sqlite3.Cursor object at 0x10a17a340>
>>> for row in db.execute('SELECT * FROM foo'):
...     print row
... 
(True,)
(False,)

2

sqlite3没有boolean类型 - 可以将字段存储为integer类型代替:

>>> import sqlite3
>>> db = sqlite3.connect(':memory:')
>>> db.execute('create table test (col1 integer)')
<sqlite3.Cursor object at 0x3737880>
>>> db.execute('insert into test values (?)', (1,))
<sqlite3.Cursor object at 0x3737960>
>>> print list(db.execute('select * from test'))
[(1,)]

一种自定义转换器类型接受存储列的字符串表示,然后你需要使用它来创建一个新的类型...

如果你做了以下事情:

db = sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES)
def myfunc(col):
    val = int(col) == 1
    print val, type(val)
    return val

sqlite3.register_converter('boolean', myfunc)

db.execute('create table blah (something boolean)')
db.executemany('insert into blah values (?)', [(True,), (False,)])
list(db.execute('select * from blah'))

您将获得一个bool类型的返回值,这是您想要的 - 但是,您需要确保处理异常,否则它们会被静默抑制...


这就是楼主试图解决的问题;你可以适应类型。 - Martijn Pieters
我知道我可以将字符串转换为整数。我的问题是为什么它一开始就给我一个字符串而不是一个整数。 - peu ping

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接