В настоящее время в версии 3.25.2 SQLite имеет ограниченную поддержку alter table. Например. Вы не можете изменить тип данных (родство типов) столбца или удалить столбец.
Обычный обходной путь - создать новую таблицу с нужной схемой, заполнить ее данными из исходной таблицы, удалить исходную таблицу и переименовать новую. Но что, если исходная таблица является родительской таблицей в отношении внешнего ключа?
Официальное решение - отключение внешних ключей, внесение необходимых изменений, а затем включение внешних ключей. Но меня немного раздражает, что это невозможно сделать в транзакции (потому что эти PRAGMA foreign_keys =
не вступают в силу внутри транзакций, поэтому их нужно выдавать до и после).
Я бы хотел использовать отложенные внешние ключи.
У меня есть 3 запроса, один из которых, кажется, работает, два других - нет. Мои вопросы следующие:
- Работает ли, казалось бы, работающий запрос по замыслу? Или это просто удачное (?) Созвездие множества факторов, и в зависимости от других таблиц или новых данных в базе данных оно может сломаться в будущем? Что-то вроде неопределенного поведения в C ++?
- Почему другие не работают? Чем они отличаются от первого?
Настройка
PRAGMA foreign_keys = OFF;
DROP TABLE IF EXISTS Parent;
CREATE TABLE Parent(A TEXT UNIQUE, COLUMN_TO_DROP FLOAT);
INSERT INTO Parent VALUES('whatever', 0.0);
DROP TABLE IF EXISTS Child;
CREATE TABLE Child(C TEXT REFERENCES Parent(A) DEFERRABLE INITIALLY DEFERRED);
INSERT INTO Child VALUES('whatever');
PRAGMA foreign_keys = ON;
Query1 - кажется, работает как задумано
BEGIN TRANSACTION;
CREATE TABLE Temp AS SELECT A FROM Parent;
DROP TABLE Parent;
CREATE TABLE Parent (A TEXT UNIQUE);
INSERT INTO Parent SELECT * FROM Temp;
DROP TABLE Temp;
COMMIT;
Query2 - создать [...] как выбор [...] не удастся
BEGIN TRANSACTION;
CREATE TABLE Temp AS SELECT A FROM Parent;
DROP TABLE Parent;
CREATE TABLE Parent AS SELECT * FROM Temp; -- different from Query1
CREATE UNIQUE INDEX ParentIndex on Parent(A); -- different from Query1
DROP TABLE Temp;
COMMIT;
Результат:
sqlite> PRAGMA foreign_key_check;
sqlite> .schema
CREATE TABLE Child(C TEXT REFERENCES Parent(A) DEFERRABLE INITIALLY DEFERRED);
CREATE TABLE Parent(A TEXT);
CREATE UNIQUE INDEX ParentIndex on Parent(A);
sqlite> SELECT * FROM Parent;
whatever
Query3 - вставка в [...] не удалась
BEGIN TRANSACTION;
CREATE TABLE Temp (A TEXT UNIQUE); -- different from Query1
INSERT INTO Temp SELECT A FROM Parent; -- different from Query1
DROP TABLE Parent;
CREATE TABLE Parent (A TEXT UNIQUE);
INSERT INTO Parent SELECT * FROM Temp;
DROP TABLE Temp;
COMMIT;
Результат:
sqlite> PRAGMA foreign_key_check;
sqlite> .schema
CREATE TABLE Child(C TEXT REFERENCES Parent(A) DEFERRABLE INITIALLY DEFERRED);
CREATE TABLE Parent (A TEXT UNIQUE);
sqlite> SELECT * FROM Parent;
whatever
Обратите внимание, что PRAGMA foreign_key_check
не сообщает ни о каких проблемах ни в одном из случаев.