Триггер для назначения номера первичного ключа из последовательности для совместного использования несколькими таблицами - PullRequest
1 голос
/ 07 мая 2019

Я в Oracle Database 18c Express Edition и APEX 19.1.

Требуется иметь возможность связывать элементы одинакового или разного типа:

  1. журналы с журналами,
  2. событий с логами
  3. ... и т. Д.

, например

logs.item_id = 1

  • logs.item_id = 2
  • events.item_id = 5

logs.item_id = 2

  • logs.item_id = 1

events.item_id = 5

  • logs.item_id = 1

Моя идея состоит в том, чтобы иметь общую последовательность идентификаторов, которая будет заполняться при каждой вставке, например, logs table.

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

https://imgur.com/Dchz7De.jpg


После выполнения сценария DDL мой первый

INSERT INTO events (dummy) VALUES ('D');

результаты с ошибкой.

ORA-02291: integrity constraint (C##TEST.EVE_ITE_FK_1) violated - parent key not found

Следующие вставки присваивают значения последовательности, начиная с 3.

https://imgur.com/ru2aewG.jpg

DROP TABLE items CASCADE CONSTRAINTS;
DROP TABLE logs CASCADE CONSTRAINTS;
DROP TABLE events CASCADE CONSTRAINTS;
DROP TABLE links CASCADE CONSTRAINTS;
DROP SEQUENCE items_seq;
DROP TRIGGER logs_trg;
DROP TRIGGER events_trg;
/
CREATE TABLE logs (
   item_id NUMBER(*,0) PRIMARY KEY
  ,dummy   CHAR(1));
/
CREATE TABLE events (
   item_id NUMBER (*,0) PRIMARY KEY
  ,dummy   CHAR(1));
/
CREATE TABLE links (
   id NUMBER(*,0) GENERATED ALWAYS AS IDENTITY PRIMARY KEY
  ,item_id_1   NUMBER(*,0)
  ,item_id_2   NUMBER(*,0));
/
CREATE TABLE items (
   id NUMBER(*,0) PRIMARY KEY
  ,type CHAR(1 CHAR));
/
ALTER TABLE logs ADD CONSTRAINT log_ite_fk_1 FOREIGN KEY (item_id) REFERENCES items (id);
/
ALTER TABLE events ADD CONSTRAINT eve_ite_fk_1 FOREIGN KEY (item_id) REFERENCES items (id);
/
ALTER TABLE links ADD CONSTRAINT lin_ite_fk_1 FOREIGN KEY (item_id_1) REFERENCES items (id);
/
ALTER TABLE links ADD CONSTRAINT lin_ite_fk_2 FOREIGN KEY (item_id_2) REFERENCES items (id);
/
CREATE SEQUENCE items_seq START WITH 1;
/
CREATE OR REPLACE TRIGGER logs_trg FOR INSERT ON logs
COMPOUND TRIGGER
   l_item_id    PLS_INTEGER      := items_seq.nextval;
   co_item_type CONSTANT CHAR(1) := 'L';
BEFORE STATEMENT 
IS 
BEGIN
   INSERT INTO items(id
                    ,type) 
   VALUES (l_item_id
          ,co_item_type);
END BEFORE STATEMENT;
BEFORE EACH ROW 
IS 
BEGIN
   SELECT l_item_id
     INTO :NEW.item_id
     FROM dual;
END BEFORE EACH ROW;
END;
/
CREATE OR REPLACE TRIGGER events_trg FOR INSERT ON events
COMPOUND TRIGGER
   l_item_id    PLS_INTEGER      := items_seq.nextval;
   co_item_type CONSTANT CHAR(1) := 'E';
BEFORE STATEMENT 
IS 
BEGIN
   INSERT INTO items(id
                    ,type) 
   VALUES (l_item_id
          ,co_item_type);
END BEFORE STATEMENT;
BEFORE EACH ROW 
IS 
BEGIN
   SELECT l_item_id
     INTO :NEW.item_id
     FROM dual;
END BEFORE EACH ROW;
END;
/

Есть ли у вас какие-либо предложения о том, что я могу сделать, чтобы он работал с 1-й вставкой?

Я ожидаю

INSERT INTO events (dummy) VALUES ('D');

для создания items.id = 1 и events.item_id = 1.


EDIT:

Следуя совету Энрике, я переключился на несоставной триггер с предложением returning - как показано ниже.

DROP TABLE items CASCADE CONSTRAINTS;
DROP TABLE logs CASCADE CONSTRAINTS;
DROP TABLE events CASCADE CONSTRAINTS;
DROP TABLE links CASCADE CONSTRAINTS;
DROP SEQUENCE items_seq;
/
CREATE TABLE logs (
   item_id NUMBER(*,0) PRIMARY KEY
  ,dummy   CHAR(1));
/
CREATE TABLE events (
   item_id NUMBER (*,0) PRIMARY KEY
  ,dummy   CHAR(1));
/
CREATE TABLE links (
   id NUMBER(*,0) GENERATED ALWAYS AS IDENTITY PRIMARY KEY
  ,item_id_1   NUMBER(*,0)
  ,item_id_2   NUMBER(*,0));
/
CREATE TABLE items (
   id NUMBER(*,0) PRIMARY KEY
  ,type CHAR(1 CHAR));
/
ALTER TABLE logs ADD CONSTRAINT log_ite_fk_1 FOREIGN KEY (item_id) REFERENCES items (id);
/
ALTER TABLE events ADD CONSTRAINT eve_ite_fk_1 FOREIGN KEY (item_id) REFERENCES items (id);
/
ALTER TABLE links ADD CONSTRAINT lin_ite_fk_1 FOREIGN KEY (item_id_1) REFERENCES items (id);
/
ALTER TABLE links ADD CONSTRAINT lin_ite_fk_2 FOREIGN KEY (item_id_2) REFERENCES items (id);
/
CREATE SEQUENCE items_seq START WITH 1;
/
CREATE OR REPLACE TRIGGER logs_trg FOR INSERT ON logs
COMPOUND TRIGGER
   l_item_id    PLS_INTEGER      := items_seq.nextval;
   co_item_type CONSTANT CHAR(1) := 'L';
BEFORE STATEMENT 
IS 
BEGIN
   INSERT INTO items(id
                    ,type) 
   VALUES (l_item_id
          ,co_item_type);
END BEFORE STATEMENT;
BEFORE EACH ROW 
IS 
BEGIN
   SELECT l_item_id
     INTO :NEW.item_id
     FROM dual;
END BEFORE EACH ROW;
END;
/
CREATE OR REPLACE TRIGGER events_trg BEFORE INSERT ON events
FOR EACH ROW
DECLARE
   co_item_type CONSTANT CHAR(1) := 'M';
BEGIN
   INSERT INTO items(id
                    ,type) 
       VALUES (items_seq.nextval
              ,co_item_type)
   RETURNING id INTO :NEW.item_id; 
   DBMS_OUTPUT.PUT_LINE(systimestamp);
END;
/
INSERT INTO events (dummy) values ('D');
INSERT INTO events (dummy) values ('D');

Теперь проблема в другом. Первая вставка в таблицу events генерирует 2 значения в items_seq

INSERT INTO events (dummy) VALUES ('D');

DBMS_OUTPUT:
08-MAY-19 11.08.29.301000000 +02:00
08-MAY-19 11.08.29.303000000 +02:00

Текущие вставки ведут себя как положено - 1 следующий номер для каждой вставки. Таким образом, 2 вставки генерируют 3 значения последовательности.

Мой желаемый результат - иметь items.id = 1 для первой вставки в таблицу events.

1 Ответ

0 голосов
/ 08 мая 2019

Просто используйте

номер v_myid;

вставьте в таблицу (col1, col2) значения (value1, value2), возвращая id в v_myid;

...