如何将外键添加到现有的SQLite表中?
我有以下表格:如何将外键添加到现有的SQLite表中?
CREATE TABLE child(
id INTEGER PRIMARY KEY,
parent_id INTEGER,
description TEXT);
如何添加上parent_id
外键约束?假设外键已启用。
大多数示例都假设您正在创建表格 - 我想将约束添加到现有表格中。
你不能。
虽然SQL-92语法外键添加到您的表将如下所示:
ALTER TABLE child ADD CONSTRAINT fk_child_parent
FOREIGN KEY (parent_id)
REFERENCES parent(id);
SQLite不支持的ADD CONSTRAINT
变体ALTER TABLE
命令(sqlite.org: SQL Features That SQLite Does Not Implement)的。
因此,在sqlite的3.6.1添加一个外键的唯一办法是在CREATE TABLE
如下:
CREATE TABLE child (
id INTEGER PRIMARY KEY,
parent_id INTEGER,
description TEXT,
FOREIGN KEY (parent_id) REFERENCES parent(id)
);
不幸的是,你必须将现有的数据保存到临时表,删除旧表,用FK约束创建新表,然后将数据从临时表中复制回来。 (sqlite.org - FAQ: Q11)
如果您更改表并添加使用约束的列,则可以添加约束。
首先,创建表而不PARENT_ID:
CREATE TABLE child(
id INTEGER PRIMARY KEY,
description TEXT);
然后,ALTER TABLE:
ALTER TABLE child ADD COLUMN parent_id INTEGER REFERENCES parent(id);
很好习惯这个序列,但是这并不回答实际问题:*我想将约束添加到现有问题。* – Wolf 2018-01-17 12:12:48
如果您使用的是Firefox插件sqlite的经理,你可以做到以下几点:
而不是再次删除和创建表,你可以像这样修改它。
在列文本框中,右键单击列出的最后一列名称以调出上下文菜单并选择编辑列。 请注意,如果TABLE定义中的最后一列是PRIMARY KEY,则需要首先添加一个新列,然后编辑新列的列类型以添加FOREIGN KEY定义。 内的列类型中,附加一个逗号和数据类型后
FOREIGN KEY (parent_id) REFERENCES parent(id)
定义。 单击更改按钮,然后单击危险操作对话框上的是按钮。
参考: Sqlite Manager
请检查https://www.sqlite.org/lang_altertable.html#otheralter
唯一模式变更命令直接SQLite的支持是 “重命名表”和“添加列”上面显示的命令。但是, 应用程序可以使用简单的操作序列对表 的格式进行其他任意更改。步骤进行是任意 更改某些表X的架构设计如下:
- 如果外键约束被启用,使用PRAGMA foreign_keys = OFF禁用它们。
- 开始交易。
- 请记住所有索引和与 表X关联的触发器的格式。此信息将在下面的步骤8中需要。 这样做的一个方法是运行如下查询:SELECT type,sql FROM sqlite_master WHERE tbl_name ='X'。
- 使用CREATE TABLE构建一个新表格“new_X”,该表格位于 希望修改的表格格式X.当然,确保名称“new_X” 不会与任何现有表名称相冲突。使用的语句从X
- 内容传送到一个new_x像:INSERT INTO SELECT的new_x ... FROM X.
- 删除旧表X:DROP TABLE X.
- 变化的new_x到X上使用的名称: ALTER TABLE的new_x重命名为X.
- 使用CREATE INDEX和CREATE TRIGGER来重建有十桌相关或许使用 触发器和索引从上述步骤3为指导保存的旧格式索引和 触发器,使 变化视情况而定。
- 如果有任何意见请参考表X在由 架构变化的影响的方式,然后使用DROP VIEW丢弃这些意见,并重新 他们与任何变化都需要使用CREATE VIEW以适应架构 变化。
- 如果最初启用了外键约束,则运行PRAGMA foreign_key_check以验证模式更改没有中断 任何外键约束。
- 提交事务在步骤2中启动。
- 如果最初启用了外键约束,现在重新启用它们 。
上述过程是完全一般的,并且即使 模式更改导致存储在表中的信息发生变化,也会工作。因此, 上面的完整过程适用于删除列, 更改列的顺序,添加或删除UNIQUE约束 或PRIMARY KEY,添加CHECK或FOREIGN KEY或NOT NULL约束, 或更改列的数据类型,例如。
首先在子表Cid
为int
然后alter table
添加一列与下面的代码。这样你就可以添加外键Cid
作为父表的主键,把它作为子表的外键...希望它会帮助你,因为它是为我好:
ALTER TABLE [child]
ADD CONSTRAINT [CId]
FOREIGN KEY ([CId])
REFERENCES [Parent]([CId])
ON DELETE CASCADE ON UPDATE NO ACTION;
GO
这在SQLite中无效。这也是MS SQL语法。 – StilesCrisis 2017-10-27 00:27:47
你能够!
请尝试以下命令,并且不需要临时表。它适用于Android Studio中的我。
db.execSQL("alter table child add column newCol integer REFERENCES parent(parentId)");
看来你没有仔细阅读过这个问题。问题是只添加一个外部约束,而不是添加一个约束列。 – Wolf 2018-01-17 12:03:52
是的,你可以,无需添加新的列。你必须要小心,这样做正确,以避免损坏数据库,所以你应该完全备份您的数据库试图在此之前:
pragma writable_schema=1;
// replace the entire table's SQL definition, where new_sql_definition contains the foreign key clause you want to add
UPDATE SQLITE_MASTER SET SQL = new_sql_definition where name = 'child' and type = 'table';
// alternatively, you might find it easier to use replace, if you can match the exact end of the sql definition
// for example, if the last column was my_last_column integer not null:
UPDATE SQLITE_MASTER SET SQL = replace(sql, 'my_last_column integer not null', 'my_last_column integer not null, foreign key (col1, col2) references other_table(col1, col2)') where name = 'child' and type = 'table';
pragma writable_schema=0;
无论哪种方式,你可能会想先看看有什么SQL定义是你在进行任何更改之前:如果您使用的替换()方法
select sql from SQLITE_MASTER where name = 'child' and type = 'table';
,你会发现它有用,在执行之前,通过运行第一测试代替()命令:
select update(sql, ...) from SQLITE_MASTER where name = 'child' and type = 'table';
我认为重命名旧表更容易,创建新表并将数据复制回来。然后,您可以删除旧表。 – tuinstoel 2009-12-11 19:20:24
是的,那很容易。我只是引用了sqlite的常见问题:http://www.sqlite.org/faq.html#q11。实际上,'RENAME TO'是sqlite 3当前支持的少数几个'ALTER TABLE'变体之一。 – 2009-12-11 19:37:51
不应该是: FOREIGN KEY(parent_id)REFERENCES父级(id) 确实,Jonathan没有给出“父表”的名称。 其实表格应该是人名,但是... – igorludi 2012-09-07 08:51:29