This question already has an answer here:
Add ON DELETE CASCADE behavior to an sqlite3 table after it has been created
(1 answer)
Closed 5 years ago.
I am adding constraints to tables in Sqlite as following:
alter table TagsI18N
add constraint FK_TagsI18N_TagId foreign key (TagId) references Tag(Id) on delete cascade on update cascade,
constraint FK_TagsI18N_LanguageCode foreign key (LanguageCode) references [Languages](Code) on delete cascade on update cascade;
I was using this code in SQL Server database but is not being accepted in SQLite.
How can I create such a constraint in Sqlite?
The ALTER command in SQLite3 is limited to adding columns or renaming tables, so you cannot do this. Instead, you must re-create the table with the desired constraints.
Related
I have a Xamarin.Forms app that uses a SQLite database locally on the device. Here's some sample data structure:
Table x: id, name
Table y: id, name
Table x_y: id, x_id, y_id
Since SQLite doesn't support altering columns, one of the schema updates we sent down in a patch did the following:
Rename table x to x_temp
Create new/updated table x
Insert all data from table x_temp into table x
Drop table if exists x
That seems to work just fine. However, when I'm attempting to run an insert statement on table x_y, I am getting a SQLite exception: "no such table: main.x_temp".
When I look at the SQLite query string while debugging there is no mention of table x_temp whatsoever. So, if I delete the entire database and re-create everything the insert works just fine.
I'm from a MSSQL background, am I not understanding something about SQLite in general? Is the foreign key constraint from table x_y trying to reference x_temp because I renamed the original table (I may have just answered my own question)? If that's the case, surely there is a way around this without having to cascade and re-create every table?
Any input would be appreciated. Thanks!
I believe that your issue may be related to the SQlite version in conjunction with whether or not Foreign Key Support has been turned on.
That is the likliehood is that :-
Is the foreign key constraint from table x_y trying to reference
x_temp because I renamed the original table (I may have just answered
my own question)?
Would be the issue, as you likely have Foreign Key Support turned on as per :-
Prior to version 3.26.0 (2018-12-01), FOREIGN KEY references to a table that is renamed were only edited if the PRAGMA foreign_keys=ON, or in other words if foreign key constraints were begin enforced.
With PRAGMA foreign_keys=OFF, FOREIGN KEY constraints would not be changed when the table that the foreign key referred to (the "parent table") was renamed.
Beginning with version 3.26.0, FOREIGN KEY constraints are always converted when a table is renamed, unless the PRAGMA legacy_alter_table=ON setting is engaged. The following table summaries the difference:
SQL As Understood By SQLite - ALTER TABLE
If that's the case, surely there is a way around this without having
to cascade and re-create every table?
Yes, as the latest version of SQlite on Android is 3.19.0 (I believe), then you can turn Foreign Key support off using the foreign_keys pragma when renaming the table.
Note Foreign Keys cannot be turned off within a transaction.
See SQL As Understood By SQLite - ALTER TABLE and PRAGMA foreign_keys = boolean;
Is it possible to add an ON DELETE CASCADE to a table after it has been created?
My schema is as follows:
CREATE TABLE skills(name varchar, skill varchar, level int, foreign key(name) references runners(name), primary key(name, skill));
And I would like to cascade if the foreign key is deleted.
SQLite's ALTER TABLE command cannot do what you want.
However, it is possible to bypass the SQL interpreter and change the internal table definition directly.
SQLite stores table definitions as a textual copy of the CREATE TABLE command in its sqlite_master table; check out the result of this query:
SELECT sql FROM sqlite_master WHERE type='table' AND name='skills';
Add your cascade specification to that string, then enable write access to sqlite_master with PRAGMA writable_schema=1; and write your new table definition into it:
UPDATE sqlite_master SET sql='...' WHERE type='table' AND name='skills';
Then reopen the database.
WARNING: This works only for changes that do not change the on-disk format of the table. If you do make any change that changes the record format (such as adding/removing fields, or modifying the rowid), your database will blow up horribly.
This question already has an answer here:
Error when trying to update sqlite database in android
(1 answer)
Closed 6 years ago.
Working with the artist/tracks example at https://www.sqlite.org/foreignkeys.html
I'd like to drop both tables. I would think that if I first drop tracks (which References artist) I could then drop artists:
stat_5.executeUpdate("drop table if exists tracks;");
stat_6.executeUpdate("drop table if exists artist;");
But this issues an exception "SQLException: foreign key constraint failed"
What am I missing?
The documentation says:
If foreign key constraints are enabled, a DROP TABLE command performs an implicit DELETE FROM command before removing the table from the database schema. [...] If the implicit DELETE FROM executed as part of a DROP TABLE command violates any immediate foreign key constraints, an error is returned and the table is not dropped.
Remove the data in the correct order so that all intermediate steps are valid.
Or just disable foreign constraint checking.
Is it possible to add an ON DELETE CASCADE to a table after it has been created?
My schema is as follows:
CREATE TABLE skills(name varchar, skill varchar, level int, foreign key(name) references runners(name), primary key(name, skill));
And I would like to cascade if the foreign key is deleted.
SQLite's ALTER TABLE command cannot do what you want.
However, it is possible to bypass the SQL interpreter and change the internal table definition directly.
SQLite stores table definitions as a textual copy of the CREATE TABLE command in its sqlite_master table; check out the result of this query:
SELECT sql FROM sqlite_master WHERE type='table' AND name='skills';
Add your cascade specification to that string, then enable write access to sqlite_master with PRAGMA writable_schema=1; and write your new table definition into it:
UPDATE sqlite_master SET sql='...' WHERE type='table' AND name='skills';
Then reopen the database.
WARNING: This works only for changes that do not change the on-disk format of the table. If you do make any change that changes the record format (such as adding/removing fields, or modifying the rowid), your database will blow up horribly.
This question already has answers here:
Does SQLite3 not support foreign key constraints?
(5 answers)
Closed 11 months ago.
The following is a query for creating a table:
CREATE TABLE "FacilityRating"(
"FacilityRatingId" INTEGER PRIMARY KEY NOT NULL,
"Stars" VARCHAR,
"Facility_FacilityId" INTEGER,
"User_UserId" INTEGER,
FOREIGN KEY (Facility_FacilityId)
REFERENCES Facility(FacilityId)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (User_UserId)
REFERENCES User(UserId)
ON DELETE CASCADE
ON UPDATE CASCADE
)
However, when I insert a new row in Facility_FacilityId and User_UserId with some random numbers, SQLite does not give error but adds it anyway.
Here is a snapshot:
Any hint what is going on here? I am using SQLite Manager, an Add-on for Mozilla Firefox
The documentation says:
Foreign key constraints must be enabled by the application at runtime, using the PRAGMA foreign_keys command. For example:
sqlite> PRAGMA foreign_keys = ON;
Foreign key constraints are disabled by default (for backwards compatibility), so must be enabled separately for each database connection.
#Override
public void onConfigure(SQLiteDatabase db) {
super.onConfigure(db);
db.setForeignKeyConstraintsEnabled(true);
}