Проблемы внешнего ключа Oracle с многостольными вставками и BLOB-объектами - PullRequest
2 голосов
/ 11 ноября 2010

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

Я не думаю, что это нарушает правила для многостоловых вставок , но я могу ошибаться ...

Я надеюсь, что кто-то может подсказать мне более подробные ресурсы о том, что на самом деле здесь происходит, так что я могу быть уверен, что любое решение будет работать как часть набора изменений в жидкой базе в базах данных 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 (которые будут содержать информацию о вещах типа 'one' или '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. Временное отключение ограничений внешнего ключа

<code>ALTER TABLE dest_one DISABLE CONSTRAINT XFK1DEST_ONE;</p>

<p>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');</p>

<p>ALTER TABLE dest_one ENABLE CONSTRAINT XFK1DEST_ONE;

Это решение, к которому я склоняюсь. Хотя отключение внешнего ключа на моей таблице больших двоичных объектов, кажется, заставляет его работать в моей тестовой среде (10g - 10.2.0.1.0), я не уверен, следует ли мне также отключать внешний ключ на таблице без больших двоичных объектов. (из-за того, как могут вести себя 9i, 11g или другие версии 10g). Любые ресурсы здесь тоже будут оценены.

Спасибо большое!

1 Ответ

2 голосов
/ 11 ноября 2010

Другим решением было бы отложить оценку ограничения до COMMIT.Я подозреваю (но не уверен), что вставка из нескольких таблиц вставляет строки в порядке, отличном от того, который вы ожидаете и хотите.Создайте заново свои ограничения следующим образом:

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;

Это заново создает ограничения, чтобы их можно было отложить и отложить с момента их создания.Затем снова попробуйте свой оригинальный INSERT.

Поделитесь и наслаждайтесь.

...