触发从序列中分配主键号,以供多个表共享

时间:2019-05-07 11:51:24

标签: oracle plsql oracle-apex

我正在使用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

我的想法是要有一个共享的ID序列,该序列将在每次插入时填充-例如-日志表。

对于日志事件和其他项目具有唯一的ID,我可以在单独的链接表中创建链接

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;
/

您对我如何使它与第一个插入物一起使用有任何建议吗?

我希望

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

生成items.id = 1和events.item_id = 1。


编辑:

按照Enrique的建议,我使用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表上的第一个插入在items_seq上生成2个值

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表上首次插入events = 1。

1 个答案:

答案 0 :(得分:0)

只需使用此

v_myid号;

插入表(col1,col2)     值(value1,value2)     将id返回到v_myid;