如何向现有 SQLite 表添加外键?

我有下表:

CREATE TABLE child(
id INTEGER PRIMARY KEY,
parent_id INTEGER,
description TEXT);

如何在 parent_id上添加外键约束? 假设启用了外键。

大多数示例假设您正在创建表——我想将约束添加到现有的表中。

164776 次浏览

你不能

尽管向表中添加外键的 SQL-92语法如下:

ALTER TABLE child ADD CONSTRAINT fk_child_parent
FOREIGN KEY (parent_id)
REFERENCES parent(id);

SQLite 不支持 ALTER TABLE命令(Org: SQLite 不实现的 SQL 特性)的 ADD CONSTRAINT变体。

因此,在 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 约束创建新表,然后将数据从临时表中复制回来。(Org-FAQ: Q11 sqlite.org-常见问题:)

如果更改表并添加使用该约束的列,则可以添加该约束。

首先,创建没有 father _ id 的表:

CREATE TABLE child(
id INTEGER PRIMARY KEY,
description TEXT);

然后,更改表:

ALTER TABLE child ADD COLUMN parent_id INTEGER REFERENCES parent(id);

如果您正在使用 Firefox 附加组件 sqlite-manager,您可以执行以下操作:

不需要再次删除和创建表,只需要像这样修改它即可。

在“列”文本框中,右键单击列出的最后一个列名,打开上下文菜单并选择“编辑列”。 注意,如果 TABLE 定义中的最后一列是 PRIMARYKEY,那么需要首先添加一个新列,然后编辑新列的列类型,以便添加 FOREIGNKEY 定义。 在“列类型”框中,添加逗号和

FOREIGN KEY (parent_id) REFERENCES parent(id)

数据类型后的定义。 单击“更改”按钮,然后单击“危险操作”对话框上的“是”按钮。

参考文献: Sqlite 经理

请检查 https://www.sqlite.org/lang_altertable.html#otheralter

SQLite 直接支持的唯一架构修改命令是 “重命名表”和“添加列”命令, 应用程序可以对表的格式进行其他任意更改 使用一个简单的操作序列 对某些表 X 的架构设计的更改如下:

  1. 如果启用了外键约束,请使用 PRAGMA 禁用它们 Foreign _ keys = OFF.
  2. 开始交易。
  3. 关联的所有索引和触发器的格式 这些信息将需要在下面的步骤8中提供 这样做的目的是运行如下查询: SELECT 类型,sqlFROM Sqlite _ master WHERE tbl _ name = ‘ X’。
  4. 使用 CREATETABLE 构造一个新表“ new _ X”,该表位于 需要修改表 X 的格式。确保名称“ new _ X” 当然,不会与任何现有的表名冲突。
  5. 使用如下语句将内容从 X 传输到 new _ X: INSERT 进入 new _ X SELECT... FROM X。
  6. 删除旧表 X: 删除表 X。
  7. 使用 ALTER TABLE new _ X RENAME TO X 将 new _ X 的名称更改为 X。
  8. 使用 CREATEINDEX 和 CREATETRIGGER 重新构造索引和 与表 X 关联的触发器 从上面的步骤3中保存的触发器和索引作为指南,使 更改。
  9. 如果任何视图引用表 X 的方式受 模式更改,然后使用 DROPVIEW 删除这些视图并重新创建 为了适应模式,它们需要做任何必要的更改 使用 CREATE 视图进行更改。
  10. 如果最初启用了外键约束,那么运行 PRAGMA Foreign _ key _ check 来验证架构更改没有中断 任何外键约束。
  11. 提交在步骤2中开始的事务。
  12. 如果最初启用了外键约束,则重新启用它们 现在。

上面的过程是完全通用的,即使 架构更改会导致存储在表中的信息发生更改 上面的完整过程适用于删除列, 更改列的顺序,添加或移除 UNIQUE 约束 或主键,添加 CHECK、外键或 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

基本上你不能,但你可以绕过这种情况。

将外键约束添加到现有表的正确方法是以下命令。

db.execSQL("alter table child add column newCol integer REFERENCES parent(parent_Id)");

然后将 原文地址数据复制到 新上校,然后删除 Parent _ Id列。 因此,不需要临时表。

可以,但不需要添加新列。为了避免损坏数据库,必须小心正确地执行此操作,因此在尝试此操作之前应该完全备份数据库。

举个具体的例子:

CREATE TABLE child(
id INTEGER PRIMARY KEY,
parent_id INTEGER,
description TEXT
);


--- create the table we want to reference
create table parent(id integer not null primary key);


--- now we add the foreign key
pragma writable_schema=1;
update SQLITE_MASTER set sql = replace(sql, 'description TEXT)',
'description TEXT, foreign key (parent_id) references parent(id))'
) where name = 'child' and type = 'table';


--- test the foreign key
pragma foreign_keys=on;
insert into parent values(1);
insert into child values(1, 1, 'hi'); --- works
insert into child values(2, 2, 'bye'); --- fails, foreign key violation

或者更一般地说:

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';

如果您使用 place ()方法,您可能会发现在执行之前,通过运行以下命令来首先测试自己的 place ()命令是很有帮助的:

select replace(sql, ...) from SQLITE_MASTER where name = 'child' and type = 'table';

你可以试试这个:

ALTER TABLE [Child] ADD COLUMN column_name INTEGER REFERENCES parent_table_name(column_id);

如果您使用 Db Browser for sqlite,那么修改表就很容易。您可以在现有表中添加外键,而无需编写查询。

  • 在数据库浏览器中打开数据库,
  • 只要右键点击表格,然后点击修改,
  • 在那里滚动到外键列,
  • 双击要更改的字段,
  • 然后选择 table and it’s field 并单击 ok。

就是这样。您成功地在现有表中添加了外键。

创建现有 SQLLite 表的外键:

对于 SQLLITE,没有直接的方法可以做到这一点。运行以下查询以使用外键重新创建学生表。 在创建了初始的学生表并将数据插入到表中之后运行查询。

CREATE TABLE    STUDENTS    (
STUDENT_ID  INT NOT NULL,
FIRST_NAME  VARCHAR(50) NOT NULL,
LAST_NAME   VARCHAR(50) NOT NULL,
CITY    VARCHAR(50) DEFAULT NULL,
BADGE_NO    INT DEFAULT NULL
PRIMARY KEY(STUDENT_ID)
);

将数据插入学生表。

然后添加外键: 使 BADGE _ NO 作为同一学生表的外键

BEGIN;
CREATE TABLE STUDENTS_new (
STUDENT_ID  INT NOT NULL,
FIRST_NAME  VARCHAR(50) NOT NULL,
LAST_NAME   VARCHAR(50) NOT NULL,
CITY    VARCHAR(50) DEFAULT NULL,
BADGE_NO    INT DEFAULT NULL,
PRIMARY KEY(STUDENT_ID) ,
FOREIGN KEY(BADGE_NO) REFERENCES STUDENTS(STUDENT_ID)
);
INSERT INTO STUDENTS_new SELECT * FROM STUDENTS;
DROP TABLE STUDENTS;
ALTER TABLE STUDENTS_new RENAME TO STUDENTS;
COMMIT;

我们也可以添加来自任何其他表的外键。

如果有人需要 SQLiteStudio 上的信息,您可以很容易地通过它的 GUI 来完成。

双击该列并双击外键行,然后勾选外键并单击 configure。可以添加引用列,然后在每个窗口中单击 OK。

最后单击绿色勾号提交结构中的更改。

请注意,这些步骤将创建删除表并重新创建表的 SQL 脚本!

从数据库备份数据。

正如 @ Daniel Vassallo所说,你不能这样做。你必须使用的代码是这样的:

根据表格:

CREATE TABLE child(
id INTEGER PRIMARY KEY,
parent_id INTEGER,
description TEXT);

我假设您想添加以下 Foreignk Key:

FOREIGN KEY (parent_id) REFERENCES parent(id);

所以我会基于这个表创建一个临时表,然后我会创建一个新的表,作为第一个,但使用外键,最后我会添加临时表的数据到它:

CREATE TEMPORARY TABLE temp AS
SELECT
id,
parent_id,
description
FROM child;


DROP TABLE child;


CREATE TABLE child (
id INTEGER PRIMARY KEY,
parent_id INTEGER,
description TEXT,
FOREIGN KEY(parent_id) REFERENCES parent(id));


INSERT INTO child
(  id,
parent_id,
description)
SELECT
id,
parent_id,
description
FROM temp;

为了直观地完成@Gaurav Ganani 的解释,这对我来说很好用(我希望它对那些使用 SQLite 数据库浏览器的人也很好用) ,让我把这个图片粘贴到这里:

enter image description here