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

How do I add a foreign key to an existing SQLite table?

提问人:Dane O'Connor 提问时间:12/11/2009 最后编辑:WolfDane O'Connor 更新时间:12/17/2022 访问量:187658

问:

我有下表:

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

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

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

sql sqlite 外键 ddl

评论

1赞 situee 2/19/2019
SQLite ALTER 命令仅支持“重命名表”和“添加列”。但是,我们可以使用简单的操作序列对表格的格式进行其他任意更改。检查我的答案

答:

275赞 Daniel Vassallo 12/11/2009 #1

你不能。

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

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

SQLite 不支持命令的变体(sqlite.org:SQLite 未实现的 SQL 功能)。ADD CONSTRAINTALTER TABLE

因此,在 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 - 常见问题:Q11)

评论

38赞 tuinstoel 12/12/2009
我认为重命名旧表、创建新表并将数据复制回更容易。然后,您可以删除旧表。
0赞 Daniel Vassallo 12/12/2009
是的,这更容易。我只是引用了sqlite常见问题解答:sqlite.org/faq.html#q11。事实上,这是 sqlite 3 中目前支持的少数变体之一。RENAME TOALTER TABLE
3赞 igorludi 9/7/2012
不应该是: FOREIGN KEY (parent_id) REFERENCES parent(id) 没错,Jonathan 没有给出“父表”的名称。其实,这张表应该命名为人,但是......
4赞 nagylzs 3/15/2014
这对我来说似乎是一个大问题。通常,在转储数据库时,首先导出 CREATE TABLE 命令。然后是 INSERT INTO 命令,最后是 ADD CONSTRAINT 命令。如果数据中存在循环(外键值)依赖关系,则在强制使用外键时无法插入数据。但是,如果以后不能添加外键约束,那么就卡住了。当然有延迟的约束,但这是非常笨拙的。
19赞 Alex Zaitsev 9/18/2014
如果其他表引用了此表,请不要重命名第一条注释中所说的旧表!在这种情况下,您还必须重新创建所有这些表。
83赞 Jorge Novaes 5/10/2014 #2

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

首先,创建不带parent_id的表:

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

然后,更改表:

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

评论

5赞 Wolf 1/17/2018
很高兴习惯这个序列,但这并不能回答实际问题:我想将约束添加到现有约束中。
2赞 MatBailie 8/30/2020
@wolf - 我知道死灵,但是......添加新列,将值从旧列复制到新列,删除旧列。
3赞 Baso 2/9/2015 #3

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

与其删除并再次创建表,不如像这样修改它。

在“列”文本框中,右键单击列出的最后一个列名称以显示上下文菜单,然后选择“编辑列”。 请注意,如果 TABLE 定义中的最后一列是 PRIMARY KEY,则需要先添加一个新列,然后编辑新列的列类型才能添加 FOREIGN KEY 定义。 在“列类型”框中,附加一个逗号和

FOREIGN KEY (parent_id) REFERENCES parent(id)

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

参考:Sqlite 管理器

14赞 situee 3/5/2015 #4

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

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

  1. 如果启用了外键约束,请使用 PRAGMA 禁用它们 foreign_keys=关闭。
  2. 开始交易。
  3. 记住与 表 X.在下面的步骤 8 中将需要此信息。一种方式 执行此操作是为了运行如下所示的查询:SELECT type, sql FROM sqlite_master 其中 tbl_name='X'。
  4. 使用 CREATE TABLE 构造一个新表 “new_X”,该表位于 希望修改表X的格式。 确保名称“new_X” 当然,不会与任何现有的表名发生冲突。
  5. 使用如下语句将内容从 X 传输到 new_X:INSERT 进入new_X选择...从 X。
  6. 删除旧表 X:DROP TABLE X。
  7. 使用以下命令将 new_X 的名称更改为 X:ALTER TABLE new_X RENAME TO X。
  8. 使用 CREATE INDEX 和 CREATE TRIGGER 重建索引和 与表 X 关联的触发器。也许使用 从上述步骤 3 中保存的触发器和索引作为指南,使 根据更改进行适当的更改。
  9. 如果任何视图以受 架构更改,然后使用 DROP VIEW 删除这些视图并重新创建 它们具有适应架构所需的任何更改 使用 CREATE VIEW 进行更改。
  10. 如果最初启用了外键约束,则运行 PRAGMA foreign_key_check验证架构更改是否未中断 任何外键约束。
  11. 提交在步骤 2 中启动的事务。
  12. 如果最初启用了外键约束,请重新启用它们 现在。

上述过程是完全通用的,即使 架构更改会导致表中存储的信息发生更改。所以 上面的完整过程适用于删除列, 更改列的顺序,添加或删除 UNIQUE 约束 或 PRIMARY KEY,添加 CHECK 或 FOREIGN KEY 或 NOT NULL 约束, 或更改列的数据类型。

-3赞 Tariq Nawaz Khan 7/26/2016 #5

首先在子表中添加一列,然后使用下面的代码。这样,您就可以将外键添加为父表的主键,并将其用作子表中的外键...希望它能对你有所帮助,因为它对我有好处:Cidintalter tableCid

ALTER TABLE [child] 
  ADD CONSTRAINT [CId] 
  FOREIGN KEY ([CId]) 
  REFERENCES [Parent]([CId]) 
  ON DELETE CASCADE ON UPDATE NO ACTION;
GO

评论

2赞 StilesCrisis 10/27/2017
这在SQLite中无效。这也是MS SQL语法。
-2赞 saeed khalafinejad 11/20/2016 #6

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

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

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

然后将parent_Id数据复制到 newCol,然后删除 Parent_Id 列。 因此,不需要临时表。

评论

0赞 Wolf 1/17/2018
看来你没有仔细阅读这个问题。问题在于仅添加外部约束,而不是添加具有约束的列。
0赞 M.K 2/15/2019
不。它没有回答提出的问题。
15赞 mwag 12/29/2017 #7

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

对于您的具体示例:

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

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

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

评论

2赞 Paulo Freitas 3/19/2023
这对我来说是更简单的解决方案,感谢您的分享!:)
5赞 Jamshy EK 2/8/2019 #8

你可以试试这个:

ALTER TABLE [Child] ADD COLUMN column_name INTEGER REFERENCES parent_table_name(column_id);
4赞 Gaurav Vanani 9/19/2020 #9

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

  • 在数据库浏览器中打开数据库,
  • 只需右键单击表格并单击修改,
  • 在那里滚动到外键列,
  • 双击要更改的字段,
  • 然后选择表及其字段,然后单击确定。

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

评论

2赞 loris 8/16/2021
我可以使用DB Browser版本3.10.1执行此操作,但是不会保存信息。如果进行更改,请单击“确定”,然后再次单击“修改”,更改已消失。这适用于哪个版本?
0赞 sscalvo 5/26/2022
它对我来说很顺利!我在下面添加了一个图像,因为 GUI 不是直截了当的,我不清楚滚动必须是水平的。谢谢!
0赞 Metro Smurf 12/17/2022
@loris - 我相当确定您必须在进行任何修改后提交更改。使用菜单:。File > Write Changes
2赞 passionatedevops 10/12/2020 #10

为现有 SQLLite 表创建外键:

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

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

将数据插入到 STUDENTS 表中。

然后添加 FOREIGN KEY:使 BADGE_NO 作为同一个 STUDENTS 表的外键

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;

我们也可以从任何其他表中添加外键。

0赞 szilkov 10/20/2020 #11

如果其他人需要有关SQLiteStudio的信息,您可以轻松地通过其GUI进行操作。

双击该列并双击外键行,然后勾选外键并单击配置。您可以添加引用列,然后在每个窗口中单击“确定”。

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

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

从数据库备份数据。

7赞 AngryCoder 5/1/2021 #12

正如瓦萨洛@Daniel所说,你做不到。您必须使用的代码如下所示:

给定表格:

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

我假设您要添加以下外来密钥:

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;

评论

1赞 foxesque 9/20/2021
不知道这个方便的速记语法来复制表格 (CREATE AS)。
0赞 sscalvo 5/26/2022 #13

只是为了在视觉上完成@Gaurav Ganani解释,这对我来说效果很好(我希望它适用于那些使用DB Browser for SQLite的人),让我将这张图片粘贴到这里:

在此处输入图像描述

0赞 Martin Harawa 12/17/2022 #14

打开数据库,右键单击表,选择“修改数据库”。 在将打开的窗口中,选择要作为外键的列,然后向右滚动,您将找到一列写外键,并轻松选择您引用的表以及该列。

评论

0赞 ahuemmer 12/20/2022
欢迎来到 SO!您的答案是指您未指定的数据库工具。这可能没有用,因为需要 DDL 命令。