162

我有下表:

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

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

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

4

12 回答 12

240

你不能。

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

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

SQLite 不支持该命令的ADD CONSTRAINT变体( sqlite.org:SQLite 不实现的 SQL 功能)。ALTER 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

于 2009-12-10T23:26:55.957 回答
69

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

首先,创建没有 parent_id 的表:

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

然后,更改表:

ALTER TABLE child ADD COLUMN parent_id INTEGER REFERENCES parent(id);
于 2014-05-09T21:12:19.950 回答
13

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

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

  1. 如果启用了外键约束,请使用 PRAGMA foreign_keys=OFF 禁用它们。
  2. 开始交易。
  3. 记住与表 X 关联的所有索引和触发器的格式。下面的第 8 步将需要这些信息。一种方法是运行如下查询:SELECT type, sql FROM sqlite_master WHERE tbl_name='X'。
  4. 使用 CREATE TABLE 构造一个新表“new_X”,该表采用表 X 的所需修订格式。当然,请确保名称“new_X”不会与任何现有表名冲突。
  5. 使用如下语句将内容从 X 传输到 new_X:INSERT INTO new_X SELECT ... FROM 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. 如果任何视图以受架构更改影响的方式引用表 X,则使用 DROP VIEW 删除这些视图,并使用 CREATE VIEW 以适应架构更改所需的任何更改重新创建它们。
  10. 如果最初启用了外键约束,则运行 PRAGMA foreign_key_check 以验证架构更改没有破坏任何外键约束。
  11. 提交在步骤 2 中开始的事务。
  12. 如果最初启用了外键约束,请立即重新启用它们。

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

于 2015-03-05T02:38:19.683 回答
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';
于 2017-12-29T03:07:05.997 回答
5

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

给定表格:

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;
于 2021-05-01T09:20:30.177 回答
3

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

可以像这样修改它,而不是再次删除和创建表。

在列文本框中,右键单击列出的最后一个列名称以调出上下文菜单并选择编辑列。请注意,如果 TABLE 定义中的最后一列是 PRIMARY KEY,则必须首先添加一个新列,然后编辑新列的列类型以添加​​ FOREIGN KEY 定义。在列类型框中,附加一个逗号和

FOREIGN KEY (parent_id) REFERENCES parent(id)

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

参考: Sqlite 管理器

于 2015-02-08T21:27:27.660 回答
3

你可以试试这个:

ALTER TABLE [Child] ADD COLUMN column_name INTEGER REFERENCES parent_table_name(column_id);
于 2019-02-08T09:39:00.320 回答
2

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

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

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

于 2020-09-19T11:51:49.663 回答
1

为现有 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;

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

于 2020-10-11T22:15:08.417 回答
0

如果其他人需要有关 SQLiteStudio 的信息,您可以通过它的 GUI 轻松完成。

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

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

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

从数据库中备份您的数据。

于 2020-10-20T13:10:22.467 回答
-2

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

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

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

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

于 2016-11-20T07:05:12.520 回答
-3

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
于 2016-07-25T17:47:28.687 回答