生成的列(有时也称为“计算列”)是表的列,其值是同一行中其他列的函数。可以读取生成的列,但不能直接写入其值。更改生成的列的值的唯一方法是修改用于计算生成的列的其他列的值。
语法上,使用“ GENERATED ALWAYS” column-constraint指定生成的列。例如:
创建表t1( 整数主键, b INT, c TEXT, d始终以虚拟形式(a * abs(b))生成的INT, e始终存储为(substr(c,b,b + 1))的文本 );
上面的语句具有三个普通列“ a”(主键),“ b”和“ c”,以及两个生成的列“ d”和“ e”。
约束开头的“ GENERATED ALWAYS”关键字和结尾处的“ VIRTUAL”或“ STORED”关键字都是可选的。仅需要“ AS”关键字和带括号的表达式。如果省略了尾随的“ VIRTUAL”或“ STORED”关键字,则默认为VIRTUAL。因此,上面的示例语句可以简化为:
创建表t1( 整数主键, b INT, c TEXT, d INT AS(a * abs(b)), e文字存储为(substr(c,b,b + 1)) );
生成的列可以是“虚拟”或“存储”。读取时将计算VIRTUAL列的值,而写入行时将计算STORED列的值。STORED列占用数据库文件中的空间,而VIRTUAL列在读取时使用更多的CPU周期。
从SQL的角度来看,STORED和VIRTUAL列几乎完全相同。对任一类生成的列的查询都会产生相同的结果。唯一的功能差异是,不能使用ALTER TABLE ADD COLUMN命令添加新的STORED列 。使用ALTER TABLE只能添加VIRTUAL列。
生成的列可以具有数据类型。SQLite尝试使用与普通列相同的相似性规则将生成表达式的结果转换为该数据类型。
就像普通列一样,生成的列可能具有NOT NULL,CHECK和UNIQUE约束以及外键约束。
就像普通列一样,生成的列可以参与索引。
生成的列的表达式可以引用表中任何其他声明的列,包括其他生成的列,只要该表达式不直接或间接地引用其自身即可。
生成的列可以出现在表定义中的任何位置。生成的列可以散布在普通列之间。如上面的示例所示,不必将生成的列放在表定义中的列列表的末尾。
生成的列可能没有默认值(它们可能不使用“ DEFAULT”子句)。生成的列的值始终是“ AS”关键字后面的表达式所指定的值。
生成的列不能用作PRIMARY KEY的一部分。(SQLite的未来版本可能会放宽对STORED列的此约束。)
生成的列的表达式只能引用同一行中的常量文字和列,并且只能使用标量确定性函数。该表达式不能使用子查询,聚合函数,窗口函数或表值函数。
生成的列的表达式可以引用同一行中的其他生成的列,但是任何生成的列都不能直接或间接依赖于自身。
尽管生成的列的表达式可以引用INTEGER PRIMARY KEY列,但生成的列的表达式可能不直接引用ROWID,这通常是同一回事。
每个表必须至少有一个非生成的列。
不能在STORED列中更改TABLE ADD COLUMN列。但是,可以添加一个VIRTUAL列。
生成的列 的数据类型和排序顺序仅由列定义上的数据类型和COLLATE子句确定。GENERATED ALWAYS AS表达式的数据类型和整理顺序对列本身的数据类型和整理顺序没有影响。
SQLite 3.31.0(2020-01-22)中添加了生成的列支持。如果SQLite的早期版本尝试读取在其架构中包含生成的列的数据库文件,则该早期版本会将生成的列语法视为错误,并将报告数据库架构已损坏。
需要说明的是:SQLite 3.31.0版可以读写SQLite 3.0.0(2004-06-18)之前的任何SQLite早期版本创建的数据库。而且,只要数据库架构不包含早期版本无法理解的功能(例如生成的列),SQLite 3.31.0之前的早期版本就可以读写SQLite 3.31.0及更高版本创建的数据库。版本。仅当使用SQLite版本3.31.0或更高版本创建包含生成的列的新数据库,然后尝试使用不理解生成的列的SQLite的较早版本尝试读取或写入该数据库文件时,才会出现问题。