“如何修复 oracle pl/sql 中的触发器?
“How to fix trigger in oracle pl/sql?
问题:
Table A 需要一个 TRIGGER,它执行以下操作:
每次INSERT在TRT_PROCEDURE列的值上做成TableA,加1
到 table B 中的 'TRT_INS_COUNT' 列。如果 TRT_PROCEDURE 值不
table B 中不存在,在table B 中添加一行用于程序设置
TRT_INS_COUNT 到 1.
每次对 Table A 进行 DELETE 时,将 1 添加到列 TRT_DEL_COUNT
table B 用于该过程值,如果它存在于 table B 中。如果它不存在
存在于table B中,在table B中添加一行用于程序并设置
TRT_DEL_COUNT 到 1.
每次对 TABLE A 中的列 TRT_PROCEDURE 进行更新时,将 1 添加到
column TRT_UPD_COUNT in table B. 如果它不在 table B 中,添加一行到
table B 作为过程值并将 TRT_UPD_COUNT 设置为 1。如果列
TRT_PROCEDURE中的值TABLEA被改变,为TRT_UPD_COUNT加1
旧程序值。
通过多次插入、删除和更新进行测试,然后显示 table B。
更新:每当将 trt_procedure 的值插入 table B 时,第二个相同的 trt_procedure(例如'88-20')无法正确计入其指定计数场地。不知道哪里出了问题。
TABLE A
Name Null Type
TRT_ID NOT NULL NUMBER(3)
PAT_NBR NUMBER(4)
PHYS_ID NUMBER(3)
TRT_PROCEDURE VARCHAR2(5)
TRT_DATE DATE
TABLE B
Name Null Type
TRT_PROCEDURE NOT NULL VARCHAR2(5)
TRT_INS_COUNT NUMBER(3)
TRT_DEL_COUNT NUMBER(3)
TRT_UPD_COUNT NUMBER(3)
TEST SAMPLES
INSERT INTO A VALUES (11, 8031,101,'88-20',sysdate );
INSERT INTO A VALUES (12, 5872,101,'60-00',sysdate );
UPDATE A SET trt_procedure = '88-20' WHERE trt_id=6;
/*row trt_id =6 cloumn trt_procedure old value '54-60'
new value '88-20', which means Table B row '88-20' and
row '54-60 both trt_upd_count should add 1*/
DELETE FROM A WHERE trt_id=1;
/*row trt_id =1 cloumn trt_procedure value also '88-20', which means
that Table B row '88-20' trt_del_count should also add 1*/
CREATE OR REPLACE TRIGGER trt_stats_trg
BEFORE INSERT OR UPDATE OR DELETE OF TRT_procedure ON A FOR EACH ROW
BEGIN
IF INSERTING THEN
UPDATE B SET trt_ins_count = trt_ins_count+1
WHERE B.trt_procedure = :new.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_ins_count)
VALUES (:new.trt_procedure, 1);
END IF;
ELSIF UPDATING THEN
UPDATE B SET trt_upd_count = trt_upd_count+1
WHERE B.trt_procedure = :old.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_upd_count)
VALUES (:old.trt_procedure, 1);
END IF;
UPDATE B SET trt_upd_count = trt_upd_count+1
WHERE B.trt_procedure = :new.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_upd_count)
VALUES (:new.trt_procedure, 1);
END IF;
ELSIF DELETING THEN
UPDATE B SET trt_del_count = trt_del_count+1
WHERE B.trt_procedure = :old.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_del_count)
VALUES (:old.trt_procedure, 1);
END IF;
END IF;
END trt_stats_trg;
在你的触发器的 IF INSERTING
部分你有
UPDATE B
SET trt_ins_count = trt_ins_count+1
WHERE :old.trt_procedure = :new.trt_procedure;
插入新行时,:OLD
伪行中的所有值均为 NULL,因此您的 UPDATE 将永远不会更新任何内容。我想你的意思是
UPDATE B
SET trt_ins_count = trt_ins_count+1
WHERE B.trt_procedure = :new.trt_procedure;
试一试,看看是否有助于解决您的问题。
给你,有一些修复。
tables:
create table a(
TRT_ID NUMBER(3) NOT NULL ,
PAT_NBR NUMBER(4),
PHYS_ID NUMBER(3),
TRT_PROCEDURE VARCHAR2(5),
TRT_DATE DATE
);
create table b(
TRT_PROCEDURE VARCHAR2(5) NOT NULL,
TRT_INS_COUNT NUMBER(3),
TRT_DEL_COUNT NUMBER(3),
TRT_UPD_COUNT NUMBER(3)
);
和触发器
CREATE OR REPLACE TRIGGER trt_stats_trg
BEFORE INSERT OR UPDATE OR DELETE ON A FOR EACH ROW
BEGIN
IF INSERTING THEN
UPDATE B SET trt_ins_count = nvl(trt_ins_count,0)+1
WHERE B.trt_procedure = :new.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_ins_count)
VALUES (:new.trt_procedure, 1);
END IF;
ELSIF UPDATING('TRT_PROCEDURE') THEN
if nvl(:old.trt_procedure, 'X') <> nvl(:new.trt_procedure, 'X') then
UPDATE B SET trt_upd_count = nvl(trt_upd_count,0)+1
WHERE B.trt_procedure = :old.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_upd_count)
VALUES (:old.trt_procedure, 1);
END IF;
UPDATE B SET trt_upd_count = nvl(trt_upd_count,0)+1
WHERE B.trt_procedure = :new.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_upd_count)
VALUES (:new.trt_procedure, 1);
END IF;
end if;
ELSIF DELETING THEN
UPDATE B SET trt_del_count = nvl(trt_del_count, 0)+1
WHERE B.trt_procedure = :old.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_del_count)
VALUES (:old.trt_procedure, 1);
END IF;
END IF;
END trt_stats_trg;
/
要点:
您可以使用 UPDATING('COLUMN_NAME')
检测 SQL 何时影响特定列。
当 UPDATING
时,您可能希望检查未更改的更新,其中值 "ABC" 的列正在更新为 "ABC"。这经常发生在仅将所有列包含在更新中的框架中,即使它们并没有真正发生变化。使用类似于 if nvl(:old.trt_procedure, 'X') <> nvl(:new.trt_procedure, 'X') then
.
的内容检测此问题
Table B
没有计数的默认值,所以当原始触发器尝试更新 table B
时,它成功了...将 NULL
更新为 NULL
,因为这就是将 1 添加到 NULL
时发生的情况。这可以通过为 table 中的列分配默认值 0
或使用 NVL(trt_upd_count,0) + 1
而不是 trt_upd_count + 1
.
[=44 来解决=]
- 最后,注意
:new
和 :old
的用法。看起来他们在此触发器中是正确的,但这将取决于您的业务案例。
问题: Table A 需要一个 TRIGGER,它执行以下操作: 每次INSERT在TRT_PROCEDURE列的值上做成TableA,加1 到 table B 中的 'TRT_INS_COUNT' 列。如果 TRT_PROCEDURE 值不 table B 中不存在,在table B 中添加一行用于程序设置 TRT_INS_COUNT 到 1.
每次对 Table A 进行 DELETE 时,将 1 添加到列 TRT_DEL_COUNT table B 用于该过程值,如果它存在于 table B 中。如果它不存在 存在于table B中,在table B中添加一行用于程序并设置 TRT_DEL_COUNT 到 1.
每次对 TABLE A 中的列 TRT_PROCEDURE 进行更新时,将 1 添加到 column TRT_UPD_COUNT in table B. 如果它不在 table B 中,添加一行到 table B 作为过程值并将 TRT_UPD_COUNT 设置为 1。如果列 TRT_PROCEDURE中的值TABLEA被改变,为TRT_UPD_COUNT加1 旧程序值。
通过多次插入、删除和更新进行测试,然后显示 table B。
更新:每当将 trt_procedure 的值插入 table B 时,第二个相同的 trt_procedure(例如'88-20')无法正确计入其指定计数场地。不知道哪里出了问题。
TABLE A
Name Null Type
TRT_ID NOT NULL NUMBER(3)
PAT_NBR NUMBER(4)
PHYS_ID NUMBER(3)
TRT_PROCEDURE VARCHAR2(5)
TRT_DATE DATE
TABLE B
Name Null Type
TRT_PROCEDURE NOT NULL VARCHAR2(5)
TRT_INS_COUNT NUMBER(3)
TRT_DEL_COUNT NUMBER(3)
TRT_UPD_COUNT NUMBER(3)
TEST SAMPLES
INSERT INTO A VALUES (11, 8031,101,'88-20',sysdate );
INSERT INTO A VALUES (12, 5872,101,'60-00',sysdate );
UPDATE A SET trt_procedure = '88-20' WHERE trt_id=6;
/*row trt_id =6 cloumn trt_procedure old value '54-60'
new value '88-20', which means Table B row '88-20' and
row '54-60 both trt_upd_count should add 1*/
DELETE FROM A WHERE trt_id=1;
/*row trt_id =1 cloumn trt_procedure value also '88-20', which means
that Table B row '88-20' trt_del_count should also add 1*/
CREATE OR REPLACE TRIGGER trt_stats_trg
BEFORE INSERT OR UPDATE OR DELETE OF TRT_procedure ON A FOR EACH ROW
BEGIN
IF INSERTING THEN
UPDATE B SET trt_ins_count = trt_ins_count+1
WHERE B.trt_procedure = :new.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_ins_count)
VALUES (:new.trt_procedure, 1);
END IF;
ELSIF UPDATING THEN
UPDATE B SET trt_upd_count = trt_upd_count+1
WHERE B.trt_procedure = :old.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_upd_count)
VALUES (:old.trt_procedure, 1);
END IF;
UPDATE B SET trt_upd_count = trt_upd_count+1
WHERE B.trt_procedure = :new.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_upd_count)
VALUES (:new.trt_procedure, 1);
END IF;
ELSIF DELETING THEN
UPDATE B SET trt_del_count = trt_del_count+1
WHERE B.trt_procedure = :old.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_del_count)
VALUES (:old.trt_procedure, 1);
END IF;
END IF;
END trt_stats_trg;
在你的触发器的 IF INSERTING
部分你有
UPDATE B
SET trt_ins_count = trt_ins_count+1
WHERE :old.trt_procedure = :new.trt_procedure;
插入新行时,:OLD
伪行中的所有值均为 NULL,因此您的 UPDATE 将永远不会更新任何内容。我想你的意思是
UPDATE B
SET trt_ins_count = trt_ins_count+1
WHERE B.trt_procedure = :new.trt_procedure;
试一试,看看是否有助于解决您的问题。
给你,有一些修复。
tables:
create table a(
TRT_ID NUMBER(3) NOT NULL ,
PAT_NBR NUMBER(4),
PHYS_ID NUMBER(3),
TRT_PROCEDURE VARCHAR2(5),
TRT_DATE DATE
);
create table b(
TRT_PROCEDURE VARCHAR2(5) NOT NULL,
TRT_INS_COUNT NUMBER(3),
TRT_DEL_COUNT NUMBER(3),
TRT_UPD_COUNT NUMBER(3)
);
和触发器
CREATE OR REPLACE TRIGGER trt_stats_trg
BEFORE INSERT OR UPDATE OR DELETE ON A FOR EACH ROW
BEGIN
IF INSERTING THEN
UPDATE B SET trt_ins_count = nvl(trt_ins_count,0)+1
WHERE B.trt_procedure = :new.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_ins_count)
VALUES (:new.trt_procedure, 1);
END IF;
ELSIF UPDATING('TRT_PROCEDURE') THEN
if nvl(:old.trt_procedure, 'X') <> nvl(:new.trt_procedure, 'X') then
UPDATE B SET trt_upd_count = nvl(trt_upd_count,0)+1
WHERE B.trt_procedure = :old.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_upd_count)
VALUES (:old.trt_procedure, 1);
END IF;
UPDATE B SET trt_upd_count = nvl(trt_upd_count,0)+1
WHERE B.trt_procedure = :new.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_upd_count)
VALUES (:new.trt_procedure, 1);
END IF;
end if;
ELSIF DELETING THEN
UPDATE B SET trt_del_count = nvl(trt_del_count, 0)+1
WHERE B.trt_procedure = :old.trt_procedure;
IF SQL%NOTFOUND THEN
INSERT INTO B (trt_procedure, trt_del_count)
VALUES (:old.trt_procedure, 1);
END IF;
END IF;
END trt_stats_trg;
/
要点:
您可以使用
UPDATING('COLUMN_NAME')
检测 SQL 何时影响特定列。当
UPDATING
时,您可能希望检查未更改的更新,其中值 "ABC" 的列正在更新为 "ABC"。这经常发生在仅将所有列包含在更新中的框架中,即使它们并没有真正发生变化。使用类似于if nvl(:old.trt_procedure, 'X') <> nvl(:new.trt_procedure, 'X') then
. 的内容检测此问题
Table
[=44 来解决=]B
没有计数的默认值,所以当原始触发器尝试更新 tableB
时,它成功了...将NULL
更新为NULL
,因为这就是将 1 添加到NULL
时发生的情况。这可以通过为 table 中的列分配默认值0
或使用NVL(trt_upd_count,0) + 1
而不是trt_upd_count + 1
.- 最后,注意
:new
和:old
的用法。看起来他们在此触发器中是正确的,但这将取决于您的业务案例。