我正在研究一个引用多个表的触发器项目。
表格结构:
CREATE TABLE TabelaA
(
id NUMBER NOT NULL,
naziv VARCHAR2(20),
datum DATE,
cijeliBroj NUMBER,
realniBroj NUMBER,
CONSTRAINT PK_TabelaA PRIMARY KEY(id),
CONSTRAINT realniBrojOgranicenjeA CHECK(realniBroj >5),
CONSTRAINT cijeliBrojOgranicenjeA CHECK(cijeliBroj NOT BETWEEN 5 AND 15)
);
CREATE TABLE TabelaB
(
id NUMBER,
naziv VARCHAR2(20),
datum DATE,
cijeliBroj NUMBER,
realniBroj NUMBER,
FKTabelaA NUMBER,
CONSTRAINT PK_TabelaB PRIMARY KEY(id),
CONSTRAINT FK_TabelaA
FOREIGN KEY(FKTabelaA) REFERENCES TabelaA(id),
CONSTRAINT cijeliBrojOgranicenjeB UNIQUE(cijeliBroj)
);
CREATE TABLE TabelaC
(
id NUMBER,
naziv VARCHAR2(20) NOT NULL,
datum DATE,
cijeliBroj NUMBER NOT NULL,
realniBroj NUMBER,
FKTabelaB NUMBER,
CONSTRAINT PK_TabelaC PRIMARY KEY(id),
CONSTRAINT FkCnst
FOREIGN KEY(FKTabelaB) REFERENCES TabelaB(id)
);
创建一个触发器 t1,在 TableB 表中添加每个新行之后,如果 TableB 表的新行的整数值小于 50,则将其在 TableA 表的相应行中的实数的值增加 25%,否则将其实数的值减少 25%。
创建一个触发器 t2,在添加或更改 TableC 表中的每一行之前,向 TableB 表添加一个新行。新行应引用 TableA 表中的同一行,作为 TableC 表的给定行引用的 TableB 表的相应行(如果有更改,则使用新值)。将今天的日期设置为新行,将 TableB 表中的最大整数值翻倍为整数,并将用于将行 1-5 初始输入到 TableB 表中的 id 的 counterB 序列的下一个值设置为。将其他列值设置为 null。如果在输入行之前未创建 counterB 序列,请稍后使用适当的设置创建它。对于使用 SQLTools 的学生,序列 counterB 必须具有最小值并从值 0 开始,对于使用 Oracle Live 的学生,序列 counterB 必须从值 1 开始。
创建一个空的备份表 TableABekap。TableABekap 表与 TableA 表完全相同,只是它有额外的列 integerB(类型为 INTEGER)和 serial(类型为 INTEGER)。
创建一个触发器 t3,该触发器填充备份表 TableABekap。在将任何新行添加到 TableB 表后,TableA 表的引用行将保存到备份表中。在此过程中,integerB 列将用 TableB 表的输入行中的整数填充。如果具有相同主键的行已输入到 TableABekap 表中,则只需将 integerB 列增加 TableB 表的输入行的 integerB 列的值。在序列列中,需要输入在触发器本身之前创建的 seq 序列的下一个值。此序列以循环顺序取 1 到 10 之间的值。对于所有学生,序列 seq 必须具有最小值并从值 1 开始(此序列不应使用值 0)。
CREATE TRIGGER t1
AFTER INSERT
ON TabelaB
FOR EACH ROW
BEGIN
IF(:NEW.cijeliBroj < 50)
THEN
UPDATE TabelaA
SET realniBroj = realniBroj * 1.25
WHERE id = :NEW.FKTabelaA;
ELSE
UPDATE TabelaA
SET realniBroj = realniBroj * 0.75
WHERE id = :NEW.FKTabelaA;
END IF;
END;
/
CREATE SEQUENCE brojacB
MINVALUE 0
START WITH 1
INCREMENT BY 1
CACHE 20;
CREATE TRIGGER t2
BEFORE INSERT OR UPDATE OR DELETE
ON TabelaC
FOR EACH ROW
DECLARE maxCijeliBroj NUMBER;
BEGIN
SELECT MAX(cijeliBroj)
INTO maxCijeliBroj
FROM TabelaB;
maxCijeliBroj := maxCijeliBroj * 2;
INSERT INTO TabelaB
VALUES (brojacB.NEXTVAL, NULL, SYSDATE, maxCijeliBroj, NULL, :NEW.FKTabelaB);
END;
/
CREATE TABLE TabelaABekap
AS
SELECT * FROM TabelaA;
ALTER TABLE TabelaABekap
ADD (cijeliBrojB NUMBER, sekvenca NUMBER);
CREATE SEQUENCE seq
MINVALUE 1
MAXVALUE 10
START WITH 1
INCREMENT BY 1
CYCLE
CACHE 9;
CREATE TRIGGER t3
AFTER INSERT
ON TabelaB
FOR EACH ROW
BEGIN
INSERT INTO TabelaABekap (id, naziv, datum, cijeliBroj, realniBroj)
SELECT id, naziv, datum, cijeliBroj, realniBroj
FROM TabelaA
WHERE id = :NEW.FKTabelaA;
DECLARE brojac INTEGER;
BEGIN
SELECT COUNT(*)
INTO brojac
FROM TabelaABekap
WHERE id = :NEW.FKTabelaA;
IF brojac > 0
THEN
UPDATE TabelaABekap
SET cijeliBrojB = cijeliBrojB + :NEW.cijeliBroj
WHERE id = :NEW.FKTabelaA;
ELSE
INSERT INTO TabelaABekap(id, naziv, datum, cijeliBroj, realniBroj, cijeliBrojB)
SELECT id, naziv, datum, cijeliBroj, realniBroj, :NEW.CijeliBroj
FROM TabelaA
WHERE id = :NEW.FKTabelaA;
END IF;
END;
UPDATE TabelaABekap
SET sekvenca = seq.NEXTVAL;
END;
/
测试用例:调用这些插入命令后:
INSERT INTO TabelaB (id, naziv, datum, cijeliBroj, realniBroj, FkTabelaA) VALUES (brojacB.nextval, null,null, 2, null, 1);
INSERT INTO TabelaB (id, naziv, datum, cijeliBroj, realniBroj, FkTabelaA) VALUES (brojacB.nextval, null,null, 4, null, 2);
INSERT INTO TabelaB (id, naziv, datum, cijeliBroj, realniBroj, FkTabelaA) VALUES (brojacB.nextval, null, null, 8, null, 1);
INSERT INTO TabelaC (id, naziv, datum, cijeliBroj, realniBroj, FkTabelaB) VALUES (4, 'NO', null, 5, null, 3);
INSERT INTO TabelaC (id, naziv, datum, cijeliBroj, realniBroj, FkTabelaB) VALUES (5, 'YES', null, 7, null,3);
INSERT INTO TabelaC (id, naziv, datum, cijeliBroj, realniBroj, FkTabelaB) VALUES (6, 'NO', null, 9, null, 2);
UPDATE TabelaC SET cijeliBroj = 10 WHERE id = 2;
DELETE FROM TabelaB WHERE id NOT IN (SELECT FkTabelaB FROM TabelaC);
DELETE FROM TabelaA WHERE id IN (3, 4, 6);
插入这些之后测试结果应该是:
SELECT SUM(id*3 + cijeliBrojB*3) FROM TabelaABekap;--Result: 2031
SELECT SUM(id*3 + cijeliBroj*3) FROM TabelaC;--Result: 420
SELECT SUM(MOD(id,10)*3) FROM TabelaB;--Result: 30
SELECT SUM(id + realniBroj)*10 FROM TabelaA;--Result: 264
我无法执行插入命令。我收到此错误以及与引用多个表、父子关系和约束相关的类似错误。
1 1 ORA-02291: 违反完整性约束 (USER.FK_TABELAA) - 未找到父键
使用的数据库:Oracle
有什么办法可以解决这个问题吗?如果您能帮助我,我将不胜感激。
您第一次向 TabelaB 插入时,对 FkTabelaA 使用值 1。TabelaB
的定义提到 FkTabelaA 必须与 TabelaA 中的现有条目相对应。但是您直接发布的 SQL 中并未提及
TabelaA 的条目 1 :因此,如果您只 执行该 SQL,那么这解释了为什么您无法在未插入相应 A 的情况下将其插入 B。
但是,您发布了一个指向 pastebin 的“填充表格”链接,其中包含表 A、B 和 C 的初始条目:
并且可以肯定的是,如果您在第一个代码块(s)和第二个代码块( s)之间播放 pastebin 的
INSERT
s , 那么您的后触发s 将起作用。CREATE TABLE
CREATE TRIGGER
INSERT
然后,您将能够调整您的
CREATE TRIGGER
s 以适应您的家庭作业的目标(但那是另一个故事,现在您只是请求帮助解除项目初始化的阻碍)。...好的,对于您的个人工作部分的第一个提示:
由于 pastebin
INSERT
会将条目 1 到 5 插入到 B 中,您可能希望
brojacB
从 6 开始您的序列,以避免基于序列的INSERT
s(触发器之后的 s)与硬编码的 s(来自 pastebin 的 s)发生冲突。