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

前端 未结 11 1655
旧时难觅i
旧时难觅i 2020-11-27 12:44

I have the following table:

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

How do I add a forei

11条回答
  •  野趣味
    野趣味 (楼主)
    2020-11-27 13:10

    Yes, you can, without adding a new column. You have to be careful to do it correctly in order to avoid corrupting the database, so you should completely back up your database before trying this.

    for your specific example:

    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
    

    or more generally:

    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;
    

    Either way, you'll probably want to first see what the SQL definition is before you make any changes:

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

    If you use the replace() approach, you may find it helpful, before executing, to first test your replace() command by running:

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

提交回复
热议问题