2009-12-10 110 views
104

我有以下表格:如何将外键添加到现有的SQLite表中?

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

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

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

回答

161

你不能。

虽然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

+19

我认为重命名旧表更容易,创建新表并将数据复制回来。然后,您可以删除旧表。 – tuinstoel 2009-12-11 19:20:24

+0

是的,那很容易。我只是引用了sqlite的常见问题:http://www.sqlite.org/faq.html#q11。实际上,'RENAME TO'是sqlite 3当前支持的少数几个'ALTER TABLE'变体之一。 – 2009-12-11 19:37:51

+3

不应该是: FOREIGN KEY(parent_id)REFERENCES父级(id) 确实,Jonathan没有给出“父表”的名称。 其实表格应该是人名,但是... – igorludi 2012-09-07 08:51:29

43

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

首先,创建表而不PARENT_ID:

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

然后,ALTER TABLE:

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

很好习惯这个序列,但是这并不回答实际问题:*我想将约束添加到现有问题。* – Wolf 2018-01-17 12:12:48

4

如果您使用的是Firefox插件sqlite的经理,你可以做到以下几点:

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

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

FOREIGN KEY (parent_id) REFERENCES parent(id) 

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

参考: Sqlite Manager

7

请检查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” 不会与任何现有表名称相冲突。使用的语句从X
  5. 内容传送到一个new_x像:INSERT INTO SELECT的new_x ... FROM X.
  6. 删除旧表X:DROP TABLE X.
  7. 变化的new_x到X上使用的名称: ALTER TABLE的new_x重命名为X.
  8. 使用CREATE INDEX和CREATE TRIGGER来重建有十桌相关或许使用 触发器和索引从上述步骤3为指导保存的旧格式索引和 触发器,使 变化视情况而定。
  9. 如果有任何意见请参考表X在由 架构变化的影响的方式,然后使用DROP VIEW丢弃这些意见,并重新 他们与任何变化都需要使用CREATE VIEW以适应架构 变化。
  10. 如果最初启用了外键约束,则运行PRAGMA foreign_key_check以验证模式更改没有中断 任何外键约束。
  11. 提交事务在步骤2中启动。
  12. 如果最初启用了外键约束,现在重新启用它们 。

上述过程是完全一般的,并且即使 模式更改导致存储在表中的信息发生变化,也会工作。因此, 上面的完整过程适用于删除列, 更改列的顺序,添加或删除UNIQUE约束 或PRIMARY KEY,添加CHECK或FOREIGN KEY或NOT NULL约束, 或更改列的数据类型,例如。

-2

首先在子表Cidint然后alter table添加一列与下面的代码。这样你就可以添加外键Cid作为父表的主键,把它作为子表的外键...希望它会帮助你,因为它是为我好:

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

这在SQLite中无效。这也是MS SQL语法。 – StilesCrisis 2017-10-27 00:27:47

-1

你能够!

请尝试以下命令,并且不需要临时表。它适用于Android Studio中的我。

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

看来你没有仔细阅读过这个问题。问题是只添加一个外部约束,而不是添加一个约束列。 – Wolf 2018-01-17 12:03:52

0

是的,你可以,无需添加新的列。你必须要小心,这样做正确,以避免损坏数据库,所以你应该完全备份您的数据库试图在此之前:

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'; 
相关问题