Оракул внешних ключевых проблем с несколькими табличными вставками и каплями
-
08-10-2019 - |
Вопрос
У нас есть единственная таблица, которую мы хотим расстаться на дереве столов на основе конкретного столбца источника. Я хотел попробовать использовать многопользовательскую вставку, но, похоже, что если я вставлю BLOB в подпалую таблицу, я заводил нарушение ограничения ключей внешнего ключа.
Я не думаю, что это нарушает Правила о многобольных вставках Но я мог быть не прав ...
Я надеюсь, что кто-то мог указать мне еще несколько углубленных ресурсов вокруг того, что на самом деле происходит здесь, чтобы я мог чувствовать себя уверенно, что какое-либо решение будет работать в рамках смешивания Liquibase на базах данных Oracle 9i -> 11G.
Надеюсь, упрощенный сценарий
CREATE TABLE source (
pk NUMBER NOT NULL PRIMARY KEY,
type VARCHAR2(20) NOT NULL,
content VARCHAR2(20) NOT NULL
);
INSERT INTO source (pk,type,content) values (1,'two','n/a');
INSERT INTO source (pk,type,content) values (2,'one','Content');
CREATE TABLE dest (
pk NUMBER NOT NULL PRIMARY KEY,
type VARCHAR2(20) NOT NULL
);
CREATE TABLE dest_one (
pkfk NUMBER NOT NULL PRIMARY KEY,
data BLOB NOT NULL,
CONSTRAINT XFK1DEST_ONE FOREIGN KEY (pkfk) REFERENCES dest (pk)
);
CREATE TABLE dest_two (
pkfk NUMBER NOT NULL PRIMARY KEY,
CONSTRAINT XFK1DEST_TWO FOREIGN KEY (pkfk) REFERENCES dest (pk)
);
Источник содержит наши исходные данные. DEST будет нашим родительским столом, с детьми dest_one и dest_two (которые будут содержать информацию о вещах типа «один» или «два» соответственно). Вещи типа у одного есть контент, но вещи типа два нет.
Неудачная попытка
INSERT ALL
WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type)
WHEN type='one' THEN INTO dest_one (pkfk,data) VALUES (pk,content)
WHEN type='two' THEN INTO dest_two (pkfk) VALUES (pk)
SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type in ('one','two');
Как уже упоминалось ранее, я завел нарушение ограниченного ключа внешнего ключа здесь. Чтобы дополнительно иллюстрировать, что BLOB был проблемой, который я попробовал два отдельных подобных запроса (ниже), реализующую то, что не работает, не выполнил вставку BLOB, но с ошибками вставки BLOB.
INSERT ALL
WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type)
WHEN type='two' THEN INTO dest_two (pkfk) VALUES (pk)
SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type = 'two';
/* Successful */
INSERT ALL
WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type)
WHEN type='one' THEN INTO dest_one (pkfk,data) VALUES (pk,content)
SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type = 'one';
/* ORA-02291: integrity constraint violated, no parent key */
Решение 1 - традиционные вставки
INSERT INTO dest (pk,type) SELECT pk,type from source where type in ('one','two');
INSERT INTO dest_two (pkfk) SELECT pk from source where type = 'two';
INSERT INTO dest_one (pkfk,data) SELECT pk,utl_raw.cast_to_raw(content) from source where type = 'one';
Один вариант, который я рассматриваю, возвращается к нескольким отдельным заявлениям вставки, но в отличие от того, как я уже говорил их здесь, я обеспокоен тем, что мне придется убедиться, что я пишу свои вкладыши под столом, чтобы только попытаться вставить эти ряды В родительском столе DEST ... Мне нужно больше исследований о том, как Liquibase обрабатывает несколько операторов SQL в тех же изменений.
Решение 2 - временно отключить ограничения внешних ключей
ALTER TABLE dest_one DISABLE CONSTRAINT XFK1DEST_ONE;
Вставьте все, когда 1 = 1, затем в значения DEST (PK, TYPE) (PK, TYPE) при типе = «один», затем в значения DEST_ONE (PKFK, DATA) (PK, Content) при типе = «два», затем в DEST_TWO ( PKFK) Значения (PK) Выберите PK, введите, utl_raw.cast_to_raw (контент) как контент из источника, где введите («один», «два»);
ALTER TABLE DEST_ONE Включить ограничение XFK1Dest_One;
Это решение, которое я склоняюсь к. Хотя отключение внешнего ключа на моем столе BLOB, кажется, заставляют его работать в моей тестовой среде (10G - 10.2.0.1.0), я не уверен, что я также должен отключить внешний ключ на таблице Nonblob (Из-за того, как 9i, 11g или другие версии 10G могут вести себя). Любые ресурсы здесь тоже будут оценены.
Огромное спасибо!
Решение
Другое решение было бы отложить оценку ограничения до коммита. Я подозреваю (но не уверен), что Multi-Table INSERT представляет собой строки в порядке, кроме того, который вы ожидаете и хотите. Воссоздайте свои ограничения следующим образом:
ALTER TABLE DEST_ONE DROP CONSTRAINT XFK1DEST_ONE;
ALTER TABLE DEST_ONE
ADD CONSTRAINT XFK1DEST_ONE
FOREIGN KEY (pkfk) REFERENCES dest (pk)
INITIALLY DEFERRED DEFERRABLE;
ALTER TABLE DEST_TWO DROP CONSTRAINT XFK1DEST_TWO;
ALTER TABLE DEST_TWO
ADD CONSTRAINT XFK1DEST_TWO
FOREIGN KEY (pkfk) REFERENCES dest (pk)
INITIALLY DEFERRED DEFERRABLE;
Это повторно создает ограничения, чтобы они могли быть отложены и отложены с момента создания времени. Затем попробуйте вашу оригинальную вставку снова.
Поделитесь и наслаждайтесь.