如何将外键添加到现有SQLite表?

时间:2009-12-10 23:22:51

标签: sql sqlite foreign-keys ddl

我有下表:

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

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

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

12 个答案:

答案 0 :(得分:181)

你不能。

虽然向表中添加外键的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

答案 1 :(得分:49)

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

首先,创建没有parent_id的表:

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

然后,改变表:

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

答案 2 :(得分:8)

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

  

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

     
      
  1. 如果启用了外键约束,请使用PRAGMA禁用它们   foreign_keys = OFF。
  2.   
  3. 开始交易。
  4.   
  5. 记住与之关联的所有索引和触发器的格式   表X.下面的步骤8将需要此信息。一种方法   这样做是运行如下所示的查询:SELECT类型,sql FROM   sqlite_master WHERE tbl_name =' X'。
  6.   
  7. 使用CREATE TABLE构建一个新表" new_X"就是在   表X的所需修改格式。确保名称" new_X"   当然,它不会与任何现有的表名冲突。
  8.   
  9. 使用如下语句将内容从X传输到new_X:INSERT   INTO new_X SELECT ... FROM X。
  10.   
  11. 删除旧表X:DROP TABLE X。
  12.   
  13. 使用以下命令将new_X的名称更改为X:ALTER TABLE new_X RENAME TO X。
  14.   
  15. 使用CREATE INDEX和CREATE TRIGGER重建索引和   与表X相关联的触发器。也许使用旧的格式   从上面的步骤3中保存的触发器和索引作为指导,制作   适当的变更。
  16.   
  17. 如果任何视图以受影响的方式引用表X.   架构更改,然后使用DROP VIEW删除这些视图并重新创建   它们需要进行任何必要的更改以适应架构   使用CREATE VIEW进行更改。
  18.   
  19. 如果最初启用了外键约束,则运行PRAGMA    foreign_key_check用于验证架构更改是否未中断    任何外键约束。
  20.   
  21. 提交在第2步中开始的交易。
  22.   
  23. 如果最初启用了外键约束,请重新启用它们    现在
  24.         

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

答案 3 :(得分:3)

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

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

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

FOREIGN KEY (parent_id) REFERENCES parent(id)
数据类型后的

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

参考: Sqlite Manager

答案 4 :(得分:3)

是的,您可以在不添加新列的情况下使用。为了避免破坏数据库,您必须小心谨慎地执行此操作,因此在尝试此操作之前应完全备份数据库。

您的具体示例:

FilterRegistrationBean

或更一般地说:

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

无论哪种方式,您可能希望在进行任何更改之前先查看SQL定义:

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;

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

select sql from SQLITE_MASTER where name = 'child' and type = 'table';

答案 5 :(得分:0)

您可以尝试以下方法:

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

答案 6 :(得分:0)

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

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

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

答案 7 :(得分:0)

创建现有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) 
);

将数据插入到学生表中。

然后添加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;

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

答案 8 :(得分:0)

如果其他人需要SQLiteStudio上的信息,则可以通过GUI轻松完成。

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

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

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

从数据库备份数据。

答案 9 :(得分:0)

正如 @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;

答案 10 :(得分:-2)

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

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

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

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

答案 11 :(得分:-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