Some table altering tasks in SQLite cannot be achieved without replacing it with a new table (by dropping - recreating the table) (like adding foreign keys, changing primary keys, updating column type). Dropping a table which has column referenced by other tables with ON DELETE CASCADE will delete all records of the child tables.
Example:
Assume that we have Table A and B. Table B has column a_id referencing (ON DELETE CASCADE) table A primary key id. For some reason I have to modify Table A by dropping and recreating table A (with original value), ALL records from table B are deleted by cascading.
I'm trying to find a workaround for this situation as mentioned in this sqlx issue and some suggestion from Matt in Discord, but none of them work:
- Try bracketing the migration with
PRAGMA foreign_keys = OFF; and PRAGMA foreign_keys = ON;:
PRAGMA foreign_keys = OFF;
create table a_temp ...;
insert into table a_temp select from a ...;
drop table a;
alter table a_temp rename to a;
PRAGMA foreign_keys = ON;
- Try bracketing the migration with
PRAGMA defer_foreign_keys = OFF; and PRAGMA defer_foreign_keys = ON;:
PRAGMA defer_foreign_keys = ON;
create table a_temp ...;
insert into table a_temp select from a ...;
drop table a;
alter table a_temp rename to a;
PRAGMA defer_foreign_keys = OFF;
- Try committing the current transaction and create a new one later:
COMMIT TRANSACTION;
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
create table a_temp ...;
insert into table a_temp select from a ...;
drop table a;
alter table a_temp rename to a;
COMMIT TRANSACTION;
PRAGMA foreign_keys=ON;
BEGIN TRANSACTION;
The workaround 1 and 2 completed but all records in table B is still deleted. The workaround 3 threw and error like this:
✘ [ERROR] Wrangler could not process the provided SQL file, as it contains several transactions.
D1 runs your SQL in a transaction for you.
Please export an SQL file from your SQLite database and try again.
Currently I have to copy data from table B to a temporally table then reinsert it to table B later.
create table b_temp;
insert into table b_temp select from b ...;
create table a_temp ...;
insert into table a_temp select from a ...;
drop table a;
alter table a_temp rename to a;
insert Into table b select from b_temp ...;
drop table b_temp;
This is a huge problem when I could have table B1, B2, B3 and more, all of them reference to table A, each table contains a few hundred thousands of records and more important, table B1, B2, B3 could be referenced from other tables too. This is really inefficient since it would definitely make a hit to billing metrics and might impact the traffic and make a migration takes longer to finish (which might affect the traffic to my D1).
Will there be a feature address this situation or is there any existing solution?
Some table altering tasks in SQLite cannot be achieved without replacing it with a new table (by dropping - recreating the table) (like adding foreign keys, changing primary keys, updating column type). Dropping a table which has column referenced by other tables with
ON DELETE CASCADEwill delete all records of the child tables.Example:
Assume that we have Table A and B. Table B has column
a_idreferencing (ON DELETE CASCADE) table A primary keyid. For some reason I have to modify Table A by dropping and recreating table A (with original value), ALL records from table B are deleted by cascading.I'm trying to find a workaround for this situation as mentioned in this sqlx issue and some suggestion from Matt in Discord, but none of them work:
PRAGMA foreign_keys = OFF;andPRAGMA foreign_keys = ON;:PRAGMA defer_foreign_keys = OFF;andPRAGMA defer_foreign_keys = ON;:The workaround
1and2completed but all records in table B is still deleted. The workaround3threw and error like this:Currently I have to copy data from table B to a temporally table then reinsert it to table B later.
This is a huge problem when I could have table B1, B2, B3 and more, all of them reference to table A, each table contains a few hundred thousands of records and more important, table B1, B2, B3 could be referenced from other tables too. This is really inefficient since it would definitely make a hit to billing metrics and might impact the traffic and make a migration takes longer to finish (which might affect the traffic to my D1).
Will there be a feature address this situation or is there any existing solution?