Вставка в формат 1: 1 - PullRequest
1 голос
/ 06 июня 2019

У меня есть две таблицы.Таблицы A и B, каждая из которых имеет первичный ключ, который автоинкрементируется, и внешний ключ не должен быть нулевымОбе таблицы находятся в соотношении 1: 1.

Итак, для каждой записи в A должен быть B.

Что я не могу получить, так это вставка в такие таблицы.Я получаю сообщение об ошибке «Родительский ключ не найден».

Я новичок в oracle, поэтому спасибо за помощь.

Вот экран ER: enter image description here

Вот моя вставка:

INSERT ALL
INTO NASTAVENI_TARIFU (ZADANI_D, ID_OBJEDNAVKY, ID_DODATKU, ID_TARIF, ID_NABIDKY) VALUES (TO_DATE('2018-01-01', 'yyyy-mm-dd' ), 1, SQ_SMLUVNI_DODATEK.nextval, 2, NULL)
INTO SMLUVNI_DODATKY (PROLONGACE_D,ID_NASTAVENI_TARIFU) VALUES (TO_DATE('2019-12-22', 'yyyy-mm-dd' ), SQ_NASTAVENI_TARIFU.currval)
SELECT * FROM DUAL

Вот определения:

CREATE TABLE nastaveni_tarifu (
    id_nastaveni_tarifu   INTEGER NOT NULL,
    zadani_d              DATE NOT NULL,
    id_objednavky         INTEGER NOT NULL,
    id_dodatku            INTEGER NOT NULL,
    id_tarif              INTEGER NOT NULL,
    id_nabidky            INTEGER
);

CREATE TABLE smluvni_dodatky (
    id_dodatku            INTEGER NOT NULL,
    prolongace_d          DATE NOT NULL,
    id_nastaveni_tarifu   INTEGER NOT NULL
);

ALTER TABLE smluvni_dodatky
    ADD CONSTRAINT fk_dodatek_nast_tarifu FOREIGN KEY ( id_nastaveni_tarifu )
        REFERENCES nastaveni_tarifu ( id_nastaveni_tarifu );

ALTER TABLE nastaveni_tarifu
    ADD CONSTRAINT fk_nast_tarifu_dodatek FOREIGN KEY ( id_dodatku )
        REFERENCES smluvni_dodatky ( id_dodatku );

CREATE SEQUENCE sq_nastaveni_tarifu START WITH 1 MINVALUE 1 NOCACHE ORDER;

CREATE OR REPLACE TRIGGER tr$ntpreinsert BEFORE
    INSERT ON nastaveni_tarifu
    FOR EACH ROW
    WHEN ( new.id_nastaveni_tarifu IS NULL )
BEGIN
    :new.id_nastaveni_tarifu := sq_nastaveni_tarifu.nextval;
END;

CREATE SEQUENCE sq_smluvni_dodatek START WITH 1 MINVALUE 1 NOCACHE ORDER;

CREATE OR REPLACE TRIGGER tr$sdpreinsert BEFORE
    INSERT ON smluvni_dodatky
    FOR EACH ROW
    WHEN ( new.id_dodatku IS NULL )
BEGIN
    :new.id_dodatku := sq_smluvni_dodatek.nextval;
END;

... Я начинаю ненавидеть Oracle, это не должнобудь таким трудным: (

1 Ответ

3 голосов
/ 06 июня 2019

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

Проблема с вашим утверждением insert all заключается в том, что второе предложение into никак не может увидеть SQ_NASTAVENI_TARIFU.nextvalпоскольку он может быть инициализирован только после завершения оператора в целом.

Даже если вы преобразуете это в 2 оператора вставки, это не сработает, потому что нет способа обеспечить наличие строки в одной таблице.когда значение зависит от другого в каждом случае, а также столбцы внешнего ключа объявляются not null.

Либо вы определяете их как NULL и пытаетесь сначала вставить пустые значения, а затем обновить его или использовать Отложенные ограничения как обходной путь * Только 1015 *.

ALTER TABLE smluvni_dodatky
    ADD CONSTRAINT fk_dodatek_nast_tarifu FOREIGN KEY ( id_nastaveni_tarifu )
        REFERENCES nastaveni_tarifu ( id_nastaveni_tarifu ) 
    deferrable initially deferred;


ALTER TABLE nastaveni_tarifu
    ADD CONSTRAINT fk_nast_tarifu_dodatek FOREIGN KEY ( id_dodatku )
        REFERENCES smluvni_dodatky ( id_dodatku ) deferrable initially deferred;

Теперь существует другая проблема со вторым триггером, если только первичный ключ таблицы smluvni_dodatky, созданный с использованиемпоследовательность sq_smluvni_dodatek может хранить то же значение, которое было вставлено в nastaveni_tarifu, постоянство не может быть поддержано.

Следовательно, в вашем Trigger tr$sdpreinsert измените aВыражение ssignment для этого

:new.id_dodatku := sq_smluvni_dodatek.currval;

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

  INSERT   INTO nastaveni_tarifu (
          zadani_d,id_objednavky,id_dodatku,id_tarif,id_nabidky
     ) VALUES (
          TO_DATE('2018-01-01','yyyy-mm-dd'), 1,sq_smluvni_dodatek.NEXTVAL, 2,NULL
     ) ;
 INSERT INTO smluvni_dodatky (
          prolongace_d,id_nastaveni_tarifu
     ) VALUES (
          TO_DATE('2019-12-22','yyyy-mm-dd'),sq_nastaveni_tarifu.currval);
commit;

DEMO

...