Я в Oracle Database 18c Express Edition и APEX 19.1.
Требуется иметь возможность связывать элементы одинакового или разного типа:
- журналы с журналами,
- событий с логами
- ... и т. Д.
, например
logs.item_id = 1
- logs.item_id = 2
- events.item_id = 5
logs.item_id = 2
events.item_id = 5
Моя идея состоит в том, чтобы иметь общую последовательность идентификаторов, которая будет заполняться при каждой вставке, например, 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
.