在编写以下内容时,我不小心在 sqlite3 的数据类型中输入了错字schema.sql
:
create table xxx(
id integer primary key autoincrement not null,
num integet
)
如您所见,integet
应该是integer
,但它仍然有效,这意味着我可以将数据插入其中。为什么?我怎样才能在integer
不破坏数据库的情况下纠正它?
正如Pythonsqlite3
模块和数据库本身的文档所解释的那样,sqlite3 是无类型的。您可以将字符串值插入一INTEGER
列,或将整数值插入一VARCHAR
列。
但是,sqlite 有一个称为“列关联”的功能,如果列类型是 INTEGER 等,它将尝试以数字方式处理参数。Python 模块尝试将每个 sqlite 类型映射到 Python 类型,所以如果 sqlite 给它INTEGER 列,Python 会将其映射到整数类型。
正如相应的文档所解释的:
如果声明的类型包含字符串“INT”,则为其分配 INTEGER 亲和性。
INTEGER int 或 long,取决于大小
比较不区分大小写。任何不符合任何规则的内容都将被视为NUMERIC
,Python 将其视为str
/ bytes
/ buffer
(取决于您的版本)。
因此,对于 sqlite 本身,integet
匹配规则INTEGER
,因此,您可以存储整数值并将它们作为整数检索。(当然,您仍然可以存储'abc'
,并将其作为字符串取回。)Python 会将其视为一INTEGER
列,因此int
尽可能读取值。
至于你问题的最后一部分,sqlite3 没有提供任何方法在创建列后更改它的类型。事实上,该ALTER TABLE
命令只允许添加新列或约束,或重命名表。
如果您需要修改实时数据库,您需要做的是创建一个包含正确列的新表,复制所有内容,删除旧表并重命名新表,如下所示:
CREATE TABLE yyy(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, num INTEGER)
INSERT INTO yyy SELECT * FROM xxx
DROP TABLE xxx
ALTER TABLE yyy RENAME TO xxx
您插入到旧表中的任何字符串值都将被复制 - 并且每次您获取它们时,因为列类型是INTEGER
,Python 将尝试转换为(int
如果可能),而不是将它们保留为bytes
or str
。
SQLite 宽容到了愚蠢的地步。您可以创建“wibble”类型的列。这个 CREATE TABLE 语句在 SQLite 中工作。
create table wibble (wibble wibble);
您也可以插入其中。
insert into wibble values ('wibble');