Small. Fast. Reliable.
Choose any three.
创建表

1.语法

创建表stmt:

CREATE TEMP TEMPORARY TABLE IF NOT EXISTS schema-name . table-name ( column-def table-constraint , ) WITHOUT ROWID , AS select-stmt

列定义:

select-stmt:

表约束:

2. CREATE TABLE命令

“创建表”命令用于在SQLite数据库中创建新表。CREATE TABLE命令指定新表的以下属性:

每个CREATE TABLE语句必须为新表指定一个名称。以“ sqlite_”开头的表名保留供内部使用。尝试创建名称以“ sqlite_”开头的表是错误的。

如果指定了架构名称,则它必须是“ main”,“ temp”或附加数据库的名称。在这种情况下,新表将在命名数据库中创建。如果在“创建”和“表”之间出现“ TEMP”或“ TEMPORARY”关键字,则将在temp数据库中创建新表。同时指定架构名称和TEMP或TEMPORARY关键字是错误的 ,除非 架构名称为“ temp”。如果未指定架构名称且不存在TEMP关键字,则在主数据库中创建表。

试图在已经包含相同名称的表,索引或视图的数据库中创建新表通常是错误的。但是,如果将“ IF NOT EXISTS”子句指定为CREATE TABLE语句的一部分,并且已经存在相同名称的表或视图,则CREATE TABLE命令将完全无效(并且不会返回错误消息)。如果由于存在索引而无法创建表,即使指定了“ IF NOT EXISTS”子句,仍然会返回错误。

创建与现有触发器同名的表不是错误。

使用DROP TABLE语句删除

2.1。CREATE TABLE ... AS SELECT语句

“ CREATE TABLE ... AS SELECT”语句根据SELECT语句的结果创建并填充数据库表。该表的列数与SELECT语句返回的行数相同。每列的名称与SELECT语句的结果集中相应列的名称相同。每列的声明类型由SELECT语句的结果集中相应表达式的表达式亲和力确定,如下所示:

表达亲和力 列声明类型
文本 “文本”
数字 “ NUM”
整数 “ INT”
真实的 “真实的”
BLOB(又名“ NONE”) “”(空字符串)

使用CREATE TABLE AS创建的表没有PRIMARY KEY,也没有任何类型的约束。每列的默认值为NULL。新表的每一列的默认排序规则序列为BINARY。

使用CREATE TABLE AS创建的表最初会填充SELECT语句返回的数据行。按SELECT语句返回的顺序,行从1开始连续分配给rowid值。

3.列定义

除非它是CREATE TABLE ... AS SELECT语句,否则CREATE TABLE包含一个或多个列定义,还可以选择包含表约束列表 。每个列定义都由列名组成,可选地后跟列的声明类型,然后是一个或多个可选列约束。就上一条语句而言,“列约束”的定义中包括COLLATE和DEFAULT子句,即使这些并不是真正的约束,因为它们并不限制表可能包含的数据。其他约束-NOT NULL,CHECK,UNIQUE,PRIMARY KEY和FOREIGN KEY约束-对表数据施加约束。

表中的列数受SQLITE_MAX_COLUMN 编译时参数的限制。表的一行不能存储超过 SQLITE_MAX_LENGTH个字节的数据。使用sqlite3_limit() C / C ++接口可以在运行时降低这两个限制。

3.1。列数据类型

与大多数SQL数据库不同,SQLite不会根据声明的列类型限制可插入到列中的数据类型。相反,SQLite使用动态类型。列的声明类型仅用于确定列的亲和力

3.2。DEFAULT子句

如果用户在执行INSERT时未明确提供任何值,则DEFAULT子句指定用于该列的默认值。如果没有显式的DEFAULT子句附加到列定义,则该列的默认值为NULL。显式的DEFAULT子句可以指定默认值为NULL,字符串常量,blob常量,带符号的数字或括号中包含的任何常量表达式。默认值也可以是与大小写无关的特殊关键字之一CURRENT_TIME,CURRENT_DATE或CURRENT_TIMESTAMP。就DEFAULT子句而言,如果表达式不包含用双引号而不是单引号引起来的子查询,列或表引用,绑定参数或字符串文字,则该表达式被视为常量。

每次通过不为所有表列提供显式值的INSERT语句将表插入表中时,存储在新行中的值均由其默认值确定,如下所示:

3.3。COLLATE子句

COLLATE子句指定排序规则序列的名称,用作该列的默认排序规则序列。如果未指定COLLATE子句,则默认排序规则序列为BINARY

3.4。GENERATED ALWAYS AS子句

包含GENERATED ALWAY AS子句的生成的列。从SQLite版本3.31.0(2020-01-22)开始支持生成的列。有关生成列的功能和限制的详细信息,请参见单独的文档

3.5。主键

SQLite中的每个表最多可以具有一个PRIMARY KEY。如果将关键字PRIMARY KEY添加到列定义,则表的主键由该单个列组成。或者,如果将PRIMARY KEY子句指定为table-constraint,则的主键由指定为PRIMARY KEY子句的一部分的列列表组成。PRIMARY KEY子句必须仅包含列名-不支持在PRIMARY KEY的索引列中使用表达式。如果CREATE TABLE语句中出现多个PRIMARY KEY子句,则会引发错误。PRIMARY KEY对于普通表是可选的,但对于WITHOUT ROWID表则是必需的。

如果表具有单个列主键,并且该列的声明类型为“ INTEGER”,并且该表不是WITHOUT ROWID表,则该列称为INTEGER PRIMARY KEY。有关与INTEGER PRIMARY KEY关联的特殊属性和行为的说明,请参见下文

具有主键的表中的每一行在其主键列中必须具有唯一的值组合。为了确定主键值的唯一性,将NULL值视为与所有其他值(包括其他NULL)不同。如果INSERTUPDATE 语句尝试修改表内容,以使两行或更多行具有相同的主键值,则违反约束。

根据SQL标准,PRIMARY KEY应该始终暗示NOT NULL。不幸的是,由于某些早期版本中的错误,在SQLite中不是这种情况。除非该列是INTEGER PRIMARY KEY或表是WITHOUT ROWID表或将该列声明为NOT NULL,否则SQLite允许在PRIMARY KEY列中使用NULL值。可以修复SQLite以使其符合标准,但是这样做可能会破坏旧版应用程序。因此,决定仅记录SQLite在大多数PRIMARY KEY列中允许NULL的事实。

3.6。唯一约束

UNIQUE约束与PRIMARY KEY约束相似,不同之处在于单个表可以具有任意数量的UNIQUE约束。对于表上的每个UNIQUE约束,每一行都必须在由UNIQUE约束标识的列中包含值的唯一组合。出于UNIQUE约束的目的,NULL值被认为与所有其他值(包括其他NULL)不同。与PRIMARY KEYs一样,UNIQUE table-constraint子句必须仅包含列名- 不支持在UNIQUE table-constraint索引列中使用表达式。

在大多数情况下,通过在数据库中创建唯一索引来实现UNIQUE和PRIMARY KEY约束。(例外是WITHOUT ROWID表上的INTEGER PRIMARY KEY和PRIMARY KEY 。)因此,以下模式在逻辑上是等效的:

  1. 创建表t1(a,b UNIQUE);

  2. 创建表t1(a,b主键);

  3. 创建表t1(a,b);
    在t1(b)上创建唯一索引t1b;

3.7。检查约束

CHECK约束可以附加到列定义或指定为表约束。实际上,这没有什么区别。每次将新行插入表中或更新现有行时,都会评估与每个CHECK约束关联的表达式,并将其转换为NUMERIC值,方法与CAST表达式相同。如果结果为零(整数值0或实数值0.0),则发生约束冲突。如果CHECK表达式的计算结果为NULL或任何其他非零值,则不是约束冲突。CHECK约束的表达式可能不包含子查询。

3.8。非空约束

NOT NULL约束只能附加到列定义,而不能指定为表约束。毫不奇怪,NOT NULL约束指示关联的列可能不包含NULL值。在插入新行或更新现有行时尝试将列值设置为NULL会导致约束冲突。

4.违反约束

约束冲突解决算法确定了如何处理 约束冲突。每个PRIMARY KEY,UNIQUE,NOT NULL和CHECK约束都有一个默认的冲突解决算法。通过在其定义中包含冲突子句,可以显式分配PRIMARY KEY,UNIQUE和NOT NULL约束,作为默认的冲突解决算法。或者,如果约束定义不包含冲突子句或它是CHECK约束,则默认冲突解决算法为ABORT。同一张表中的不同约束可能具有不同的默认冲突解决算法。有关其他信息,请参见标题为“冲突”。

5. ROWID和整数主键

除了WITHOUT ROWID表外,SQLite表中的所有行都有一个64位带符号整数键,该键唯一地标识其表中的行。该整数通常称为“ rowid”。可以使用与大小写无关的特殊名称之一“ rowid”,“ oid”或“ _rowid_”代替列名来访问rowid值。如果表包含用户定义的名为“ rowid”,“ oid”或“ _rowid_”的列,则该名称始终引用显式声明的列,并且不能用于检索整数rowid值。

WITHOUT ROWID表中省略了rowid(以及“ oid”和“ _rowid_”)。WITHOUT ROWID表仅在SQLite 3.8.2 (2013-12-06)及更高版本中可用。缺少WITHOUT ROWID子句的表称为“ rowid表”。

使用rowid值作为键,rowid表的数据存储为B树结构,其中每个表行包含一个条目。这意味着按rowid检索或排序记录很快。搜索具有特定rowid的记录,或搜索具有指定范围内的rowid的所有记录的速度大约是通过指定任何其他PRIMARY KEY或索引值进行的类似搜索的两倍。

除了下面提到的一个例外,如果rowid表的主键由单个列组成,并且该列的声明类型为大写和小写形式的“ INTEGER”,则该列将成为rowid的别名。这样的列通常称为“整数主键”。仅当声明的类型名称恰好是“ INTEGER”时,PRIMARY KEY列才成为整数主键。其他整数类型名称(例如“ INT”或“ BIGINT”或“ SHORT INTEGER”或“ UNSIGNED INTEGER”)会导致主键列的行为与具有整数相似性和唯一索引的普通表列相同,而不是作为rowid的别名。

上面提到的例外是,如果声明类型为“ INTEGER”的列的声明包含“ PRIMARY KEY DESC”子句,则它不会成为rowid的别名,也不会归类为整数主键。这个怪癖不是故意的。这是由于早期SQLite版本中的错误所致。但是修复该错误可能会导致向后不兼容。因此,原始行为得以保留(并记录在案),因为在极端情况下的奇怪行为远胜于兼容性破坏。这意味着以下三个表声明都使列“ x”成为rowid(整数主键)的别名:

但是以下声明不会导致“ x”成为rowid的别名:

可以使用UPDATE语句以与其他任何列值相同的方式修改Rowid值,可以使用内置别名之一(“ rowid”,“ oid”或“ _rowid_”),也可以使用由整数主键。同样,INSERT语句可以提供一个值,用作插入的每一行的行标识。与普通的SQLite列不同,整数主键或rowid列必须包含整数值。整数主键或rowid列不能保存浮点值,字符串,BLOB或NULL。

如果UPDATE语句尝试将整数主键或rowid列设置为NULL或blob值,或者将其设置为无法无损地转换为整数的字符串或实数值,则会发生“数据类型不匹配”错误,并且该语句将中止。如果INSERT语句尝试将blob值或无法无损地转换为整数的字符串或实值插入整数主键或rowid列,则会发生“数据类型不匹配”错误,并且该语句将中止。

如果INSERT语句尝试将NULL值插入到rowid或整数主键列中,则系统会自动选择一个整数值用作rowid。单独提供了有关此操作的详细说明 。

父键一个的外键约束,不允许使用ROWID。父键只能使用命名列。