Как добавить внешний ключ в существующую таблицу SQLite?

99

У меня есть следующая таблица:

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

Как добавить ограничение внешнего ключа на parent_id? Предположим, что включены внешние ключи.

В большинстве примеров предполагается, что вы создаете таблицу - я бы хотел добавить ограничение к существующему.

  • 0
    Команда SQLite ALTER поддерживает только «переименовать таблицу» и «добавить столбец». Однако мы можем внести другие произвольные изменения в формат таблицы, используя простую последовательность операций. Проверь мой ответ
Теги:
foreign-keys
ddl

6 ответов

156
Лучший ответ

Вы не можете.

Хотя синтаксис SQL-92 для добавления внешнего ключа в вашу таблицу будет выглядеть следующим образом:

ALTER TABLE child ADD CONSTRAINT fk_child_parent
                  FOREIGN KEY (parent_id) 
                  REFERENCES parent(id);

SQLite не поддерживает вариант ADD CONSTRAINT команды ALTER TABLE (sqlite.org: функции SQL, которые SQLite Не выполняется).

Следовательно, единственный способ добавить внешний ключ в sqlite 3.6.1 - во время CREATE TABLE следующим образом:

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

К сожалению, вам придется сохранить существующие данные во временной таблице, отбросить старую таблицу, создать новую таблицу с ограничением FK, а затем скопировать данные обратно из временной таблицы. (sqlite.org - FAQ: Q11)

  • 22
    Я думаю, что проще переименовать старую таблицу, создать новую таблицу и скопировать данные обратно. Затем вы можете удалить старую таблицу.
  • 0
    Да, так проще Я только что процитировал FAQ по sqlite: sqlite.org/faq.html#q11 . Фактически, RENAME TO является одним из немногих вариантов ALTER TABLE который в настоящее время поддерживается в sqlite 3.
Показать ещё 8 комментариев
42

Вы можете добавить ограничение, если вы измените таблицу и добавьте столбец, который использует ограничение.

Сначала создайте таблицу без parent_id:

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

Затем измените таблицу:

ALTER TABLE child ADD COLUMN parent_id INTEGER REFERENCES parent(id);
  • 1
    Хорошо привыкнуть к этой последовательности, но это не отвечает на настоящий вопрос: я хотел бы добавить ограничение к существующему.
6

Пожалуйста, проверьте https://www.sqlite.org/lang_altertable.html#otheralter

Единственными командами изменения схемы, напрямую поддерживаемыми SQLite, являются команды "переименовать таблицу" и "добавить столбец", показанные выше. Однако, приложения могут вносить другие произвольные изменения в формат таблицы используя простую последовательность операций. Шаги по созданию произвольных изменения в схеме схемы некоторой таблицы X выглядят следующим образом:

  • Если ограничения внешнего ключа включены, отключите их с помощью PRAGMA foreign_keys = OFF.
  • Запустите транзакцию.
  • Помните формат всех индексов и триггеров, связанных с таблицу X. Эта информация потребуется на шаге 8 ниже. Один из способов сделайте это, чтобы выполнить запрос следующим образом: SELECT type, sql FROM sqlite_master WHERE tbl_name = 'X'.
  • Используйте CREATE TABLE для создания новой таблицы "new_X", которая находится в желаемый пересмотренный формат таблицы X. Убедитесь, что имя "new_X" не сталкивается с каким-либо существующим именем таблицы, конечно.
  • Перенос содержимого из X в new_X с помощью оператора типа INSERT INTO new_X SELECT... FROM X.
  • Отбросьте старую таблицу X: DROP TABLE X.
  • Измените имя new_X на X, используя: ALTER TABLE new_X RENAME TO X.
  • Используйте CREATE INDEX и CREATE TRIGGER для восстановления индексов и триггеры, связанные с таблицей X. Возможно, используйте старый формат триггеры и индексы, сохраненные с шага 3 выше, в качестве руководства, изменения в зависимости от изменений.
  • Если какие-либо представления относятся к таблице X способом, на который влияет измените схему, затем отбросьте эти представления с помощью DROP VIEW и заново создайте их с любыми изменениями, необходимыми для размещения схемы с помощью CREATE VIEW.
  • Если ограничения внешнего ключа были первоначально включены, запустите PRAGMA  foreign_key_check, чтобы проверить, не изменилось ли изменение схемы  любые ограничения внешнего ключа.
  • Завершить транзакцию, начатую на шаге 2.
  • Если ограничения внешних ключей были первоначально включены, повторно их использовать  Теперь.

Процедура выше полностью общая и будет работать, даже если изменение схемы приводит к изменению информации, хранящейся в таблице. Так полная процедура выше подходит для удаления столбца, изменение порядка столбцов, добавление или удаление ограничения UNIQUE или PRIMARY KEY, добавив ограничения CHECK или FOREIGN KEY или NOT NULL, или, например, изменение типа данных для столбца.

4

Если вы используете дополнительный SQL-менеджер Firefox, вы можете сделать следующее:

Вместо того, чтобы отбрасывать и создавать таблицу снова, можно просто изменить ее следующим образом.

В текстовом поле "Столбцы" щелкните правой кнопкой мыши по последнему имени столбца, чтобы отобразить контекстное меню и выберите "Редактировать столбцы". Обратите внимание, что если последний столбец в определении TABLE является PRIMARY KEY, тогда необходимо будет сначала добавить новый столбец, а затем изменить тип столбца нового столбца, чтобы добавить определение FOREIGN KEY. В поле "Тип столбца" добавьте запятую и

FOREIGN KEY (parent_id) REFERENCES parent(id)

после типа данных. Нажмите кнопку "Изменить", а затем нажмите кнопку "Да" в диалоговом окне "Опасная операция".

Ссылка: Sqlite Manager

1

ВЫ МОЖЕТЕ!

Попробуйте выполнить следующую команду, и вам не нужна временная таблица. Это работает для меня в Android Studio.

db.execSQL("alter table child add column newCol integer REFERENCES parent(parentId)");
  • 0
    Кажется, вы не внимательно прочитали вопрос. Проблема состояла в том, чтобы добавить только внешнее ограничение, а не добавить столбец с ограничением.
  • 0
    Нету. Он не отвечает на заданный вопрос.
Показать ещё 1 комментарий
-2

Сначала добавьте столбец в дочернюю таблицу Cid как int, затем alter table с помощью кода ниже. Таким образом вы можете добавить внешний ключ Cid в качестве основного ключа родительской таблицы и использовать его в качестве внешнего ключа в дочерней таблице... надеюсь, что это поможет вам, поскольку это полезно для меня:

ALTER TABLE [child] 
  ADD CONSTRAINT [CId] 
  FOREIGN KEY ([CId]) 
  REFERENCES [Parent]([CId]) 
  ON DELETE CASCADE ON UPDATE NO ACTION;
GO
  • 1
    Это недопустимо в SQLite. Также это синтаксис MS SQL.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню