SQLite支持ALTER TABLE的有限子集。SQLite中的ALTER TABLE命令允许对现有表进行以下更改:可以重命名;可以在其中添加一列;或可以从中删除一列。
RENAME TO语法将table-name的名称更改 为new-table-name。此命令不能用于在连接的数据库之间移动表,而只能在同一数据库中重命名表。如果要重命名的表具有触发器或索引,则这些触发器或索引在重命名后仍保留在表中。
兼容性说明: 版本3.25.0(2018-09-15)和3.26.0(2018-12-01)中增强了ALTER TABLE重命名表时的行为,以便将重命名操作传递到触发器和视图中引用重命名的表。这被认为是一种改进。依赖较旧(可能是错误的)行为的应用程序可以使用 PRAGMA legacy_alter_table = ON语句或sqlite3_db_config()接口上的 SQLITE_DBCONFIG_LEGACY_ALTER_TABLE配置参数来使ALTER TABLE RENAME的行为与3.25.0版之前的行为相同。
从版本3.25.0(2018-09-15)开始,对触发器主体和视图定义中的表的引用也被重命名。
在版本3.26.0(2018-12-01)之前,仅当PRAGMA foreign_keys = ON或换句话说如果 强制执行外键约束时才编辑对重命名表的FOREIGN KEY引用 。在 PRAGMA foreign_keys = OFF的情况下,重命名外键引用的表(“父表”)时,FOREIGN KEY约束将不会更改。从3.26.0版开始,重命名表时始终会转换FOREIGN KEY约束,除非使用 PRAGMA legacy_alter_table = ON设置。下表总结了不同之处:
PRAGMA外键 PRAGMA legacy_alter_table 父表 引用已更新 SQLite版本 离开 离开 不 <3.26.0 离开 离开 是的 > = 3.26.0 上 离开 是的 全部 离开 上 不 全部 上 上 是的 全部
RENAME COLUMN TO语法将表table-name的列名更改 为new-column-name。列名在表定义本身内以及在所有引用该列的索引,触发器和视图内都发生了更改。如果列名更改将导致触发器或视图中的语义歧义,则RENAME COLUMN失败并显示错误,并且不应用任何更改。
ADD COLUMN语法用于将新列添加到现有表中。新列始终附加在现有列列表的末尾。该列的高清规则定义的新列的特性。新列可以采用CREATE TABLE 语句中允许的任何形式,但有以下限制:
还请注意,在添加CHECK约束时,不会针对表的现有行测试CHECK约束。这可能导致表中包含违反CHECK约束的数据。将来的SQLite版本可能会更改,以在添加CHECK约束时对其进行验证。
ALTER TABLE命令通过修改存储在sqlite_schema表中的模式的SQL文本来工作。对于重命名或列添加,不会对表内容进行任何更改。因此,这种ALTER TABLE命令的执行时间与表中的数据量无关。它们在具有1000万行的表上的运行速度与具有1行的表上的运行速度一样快。
在数据库上运行ADD COLUMN之后,SQLite 3.1.3(2005-02-20)及更早版本将无法读取该数据库。
DROP COLUMN语法用于从表中删除现有列。DROP COLUMN命令从表中删除命名列,并重写其内容以清除与该列关联的数据。仅当模式的任何其他部分未引用该列且该列不是PRIMARY KEY且没有UNIQUE约束时,DROP COLUMN命令才有效。DROP COLUMN命令失败的可能原因包括:
SQLite将模式以纯文本格式存储在sqlite_schema表中。DROP COLUMN命令(以及ALTER TABLE的所有其他其他变体)会修改该文本,然后尝试重新解析整个架构。仅在修改文本后架构仍然有效的情况下,该命令才成功。对于DROP COLUMN命令,唯一修改的文本是从CREATE TABLE语句中删除了列定义。如果在架构的其他部分中存在任何对列的跟踪,将阻止在修改CREATE TABLE语句后解析架构,则DROP COLUMN命令将失败。
SQLite直接支持的唯一模式更改命令是上面显示的“重命名表”,“重命名列”,“添加列”,“放置列”命令。但是,应用程序可以使用简单的操作序列对表的格式进行其他任意更改。对某些表X的架构设计进行任意更改的步骤如下:
如果启用了外键约束,请使用PRAGMA foreign_keys = OFF禁用它们。
开始交易。
请记住与表X关联的所有索引,触发器和视图的格式。在下面的步骤8中将需要此信息。一种方法是运行如下查询:SELECT类型,sql FROM sqlite_schema WHERE tbl_name ='X'。
使用CREATE TABLE来构造新的表“ new_X”,该表具有表X的所需修订格式。当然,请确保名称“ new_X”不与任何现有表名冲突。
使用以下语句将内容从X传输到new_X中:INSERT INTO new_X SELECT ... FROMX。
删除旧表X: DROP TABLE X。
使用以下命令将new_X的名称更改为X:ALTER TABLE new_X RENAME TOX。
使用CREATE INDEX,CREATE TRIGGER和CREATE VIEW 来重建与表X关联的索引,触发器和视图。也许可以使用上面第3步中保存的触发器,索引和视图的旧格式作为指导,进行相应的更改改变。
如果有任何视图以受架构更改影响的方式引用表X,则使用DROP VIEW删除那些视图,并使用CREATE VIEW进行必要的任何更改以重新创建它们以适应架构更改。
如果最初启用了外键约束,则运行PRAGMA foreign_key_check来验证架构更改没有破坏任何外键约束。
提交在步骤2中开始的事务。
如果最初启用了外键约束,请立即重新启用它们。
小心: 请务必严格按照上述步骤进行操作。下面的方框总结了修改表定义的两个过程。乍一看,他们似乎都完成了同一件事。但是,右边的过程并不总是有效,特别是在3.25.0和3.26.0版本中添加了增强的重命名表功能的情况下。在右侧的过程中,表的初始重命名为临时名称可能会破坏触发器,视图和外键约束中对该表的引用。左侧的安全过程使用新的临时名称构造修改后的表定义,然后将表重命名为其最终名称,这不会断开链接。
|
|
↑ 正确 | ↑ 不正确 |
---|
即使架构更改导致表中存储的信息发生更改,上面的12个步骤的通用ALTER TABLE过程也将起作用。因此,上述完整的12个步骤适用于删除列,更改列的顺序,添加或删除UNIQUE约束或PRIMARY KEY,添加CHECK或FOREIGN KEY或NOT NULL约束,或更改列的数据类型。例子。但是,可以选择更简单,更快速的过程进行某些更改,这些更改不会以任何方式影响磁盘上的内容。以下更简单的过程适用于删除CHECK或FOREIGN KEY或NOT NULL约束,或在列上添加,删除或更改默认值。
开始交易。
运行PRAGMA schema_version以确定当前的架构版本号。下面的步骤6需要此编号。
使用PRAGMA writable_schema = ON激活模式编辑 。
运行UPDATE语句以更改sqlite_schema表中表X的定义:UPDATE sqlite_schema SET sql = ... WHERE type ='table'AND name ='X';
警告:如此 更改sqlite_schema表,如果更改包含语法错误,将使数据库损坏且不可读。建议在包含重要数据的数据库上使用UPDATE语句之前,先在单独的空白数据库上进行仔细的测试。
如果对表X的更改也影响其他表或索引,或者触发器是架构内的视图,则运行UPDATE语句也可以修改这些其他表的索引和视图。例如,如果列名更改,则必须修改所有引用该列的FOREIGN KEY约束,触发器,索引和视图。
警告: 再次对sqlite_schema表进行这样的更改,如果更改包含错误,将使数据库损坏且不可读。在运行包含此重要数据的数据库之前,请先在单独的测试数据库上仔细测试整个过程,然后再执行此过程,然后对重要数据库进行备份。
使用PRAGMA schema_version = X递增架构版本号 ,其中X比上面步骤2中找到的旧架构版本号大1。
使用PRAGMA writable_schema = OFF禁用模式编辑 。
(可选)运行PRAGMA integrity_check以验证架构更改是否不会损坏数据库。
提交从上面的步骤1开始的事务。
如果将来的SQLite版本添加了新的ALTER TABLE功能,则这些功能很可能将使用上述两个过程之一。
大多数SQL数据库引擎将已经解析的架构存储到各种系统表中。在那些数据库引擎上,ALTER TABLE只需修改相应的系统表即可。
SQLite的不同之处在于,它将架构存储在sqlite_schema表中,作为定义架构的CREATE语句的原始文本。因此,ALTER TABLE需要修改CREATE语句的文本。对于某些“创意”方案设计,这样做可能会很棘手。
SQLite将模式存储为文本的方法对于嵌入式关系数据库具有优势。首先,这意味着该模式占用的数据库文件空间更少。这很重要,因为常见的SQLite使用模式是拥有许多小而独立的数据库文件,而不是将所有内容都放在一个大的全局数据库文件中,这是客户端/服务器数据库引擎的常用方法。由于架构在每个单独的数据库文件中重复,因此保持架构表示紧凑很重要。
将模式存储为文本而不是已解析表也为实现提供了灵活性。由于每次打开数据库时都会重新生成架构的内部解析,因此架构的内部表示形式可以从一个发行版更改为另一个发行版。这很重要,因为有时新功能需要增强内部模式表示。如果模式表示形式在数据库文件中公开,则更改内部模式表示形式将更加困难。因此,换句话说,将模式存储为文本有助于保持向后兼容性,并有助于确保较新版本的SQLite可以读取和写入较旧的数据库文件。
将模式存储为文本还可以使 SQLite数据库文件格式更易于定义,记录和理解。这有助于使SQLite数据库文件成为 推荐的存储格式,以便长期存档数据。
存储模式文本的不利之处在于,它会使修改模式变得棘手。因此,SQLite对ALTER TABLE的支持传统上落后于其他SQL数据库引擎,这些引擎将其架构存储为易于修改的已解析系统表。