SQLite - изменить родительскую таблицу в отношении внешнего ключа - PullRequest
0 голосов
/ 08 ноября 2018

В настоящее время в версии 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 не сообщает ни о каких проблемах ни в одном из случаев.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...