删除来自源 table 的 ID 的所有记录后使用触发器删除记录
Deleting Records Using a trigger once all records for an ID from the source table are deleted
我有两个 table。由于我无法共享 table 的名称,因为它太具体了,我将尝试使用通用 tables.
来解释我的查询
两个table是Score_table;它存储学生的分数,让我们说另一个 table 是一个分数仪表板 (Student_Score_Table),它提供了一个视图分数。
Score_table
|------------|------------|-------|
| Student ID | Subject ID | Score |
|------------|------------|-------|
| 12 | 1 | 50 |
|------------|------------|-------|
| 12 | 2 | 70 |
Student_Score_Table
|--------------|------------|----------|
| Student Name | Subject A | Subject B|
|--------------|------------|----------|
| Daniel | 50 | 90 |
|--------------|------------|----------|
| James | 70 | 45 |
学生和科目有各自的查找 tables 从那里我得到学生姓名和科目。
有一项服务可以更新和删除 Score_table
中的记录
我在考虑如何编写删除时遇到问题 trigger.How 我可以在这里编写一个触发器吗:-
1. 删除分数 Student_Score_Table
即当我更新 Score_table
中的值时将其设置为空
2. 当从 Score_table
中删除特定学生的所有记录时,删除 Student_Score_Table
中的整个记录
我尝试在 Score_table
上触发后写一个删除,并在使用计数查询删除 Student_Score_Table
之前检查学生是否有任何记录,但我得到的结果是“1”计数为“0”。
虽然不能 100% 确定您需要什么,但我能够使用此触发器完成我认为您正在寻求完成的事情:
CREATE OR REPLACE TRIGGER student_score_trig
AFTER
DELETE OR UPDATE of score
ON score_table
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
DELETE student_score_table
WHERE student_id = :old.student_id
;
exception
when others then
raise;
END;
Full Setup below... creating tables... inserting data and compiling trigger is all below:
CREATE TABLE score_table
( student_id NUMBER,
subject_id NUMBER,
score NUMBER
)
;
/
INSERT INTO score_table VALUES (12, 1, 50);
INSERT INTO score_table VALUES (12, 2, 70);
INSERT INTO score_table VALUES (10, 5, 60);
/
CREATE TABLE student_score_table
( student_id NUMBER,
student_name VARCHAR2(250),
subject_a NUMBER,
subject_b NUMBER
)
;
INSERT INTO student_score_table VALUES (12, 'Daniel', 50, 90);
INSERT INTO student_score_table VALUES (10, 'James', 70, 45);
/
set define off; /* Depending on your interface this line might need to be removed */
CREATE OR REPLACE TRIGGER student_score_trig
AFTER
DELETE OR UPDATE of score
ON score_table
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
DELETE student_score_table
WHERE student_id = :old.student_id
;
exception
when others then
raise;
END;
See it in Action
我不会使用单独的 table 和触发器,而是使用简单的数据透视查询:
select *
from (
select subject_name, student_name, score
from score
join students using (student_id)
join subjects using (subject_id))
pivot (max(score) for subject_name in ('Subject A', 'Subject B'))
制作一个视图,用它代替 table student_subject_score
并忘记与同步相关的触发器和问题。
您当前的解决方案使事情变得复杂。您可以在 score
上触发,但检查特定学生是否存在任何行也需要 select
在 table 分数上。这在 row-level 触发器上是不允许的,会导致 mutating table
错误。要解决这个问题,您可能需要复合触发器。此外,您的设计需要复杂的 case when
(因为我们必须找到要取消的列),或者动态的 SQL。干什么,老了,简单可靠view
解决了所有问题?
见下方更新的触发代码。与我对该问题的上次回答相比,我对触发器应用的更新确实带有一些警告。请参阅 THIS SO Post 以了解这些问题:
触发码
create or replace TRIGGER student_score_trig
AFTER
DELETE OR UPDATE of score
ON score_table
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
/* The below pragma allows us to SELECT from the same table that Triggered the Trigger.
| Many circles say that doing any 'work' on the same table as the Trigger
| is dangerous due to possible uncommited changes that are not able to be
| seen by the code within the Trigger.
*/
pragma autonomous_transaction;
n_student_count NUMBER := 0;
BEGIN
IF UPDATING THEN
/* Not sure how you plan to tie the Subjects between each of the two tables
| but I'm guessing this would be a non-issue for you.
*/
UPDATE student_score_table SET subject_a = NULL
WHERE student_id = :old.student_id
;
COMMIT;
dbms_output.put_line('This student_id was UPDATED: ' || :old.student_id || ' for subject_id: ' || :old.subject_id);
END IF;
IF DELETING THEN
SELECT COUNT(student_id)
INTO n_student_count
FROM score_table
WHERE student_id = :old.student_id
;
dbms_output.put_line(n_student_count);
IF n_student_count <= 1 THEN
DELETE student_score_table
WHERE student_id = :old.student_id
;
COMMIT;
dbms_output.put_line('This student_id was DELETED: ' || :old.student_id);
END IF;
END IF;
exception
when others then
raise;
END;
Full Setup below... creating tables... inserting data and compiling trigger is all below:
CREATE TABLE score_table
( student_id NUMBER,
subject_id NUMBER,
score NUMBER
)
;
/
INSERT INTO score_table VALUES (12, 1, 50);
INSERT INTO score_table VALUES (12, 2, 70);
INSERT INTO score_table VALUES (10, 5, 60);
/
CREATE TABLE student_score_table
( student_id NUMBER,
student_name VARCHAR2(250),
subject_a NUMBER,
subject_b NUMBER
)
;
INSERT INTO student_score_table VALUES (12, 'Daniel', 50, 90);
INSERT INTO student_score_table VALUES (10, 'James', 70, 45);
/
--set define off; /* Depending on your interface this line might need to be removed */
--/
create or replace TRIGGER student_score_trig
AFTER
DELETE OR UPDATE of score
ON score_table
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
/* The below pragma allows us to SELECT from the same table that Triggered the Trigger.
| Many circles say that doing any 'work' on the same table as the Trigger
| is dangerous due to possible uncommited changes that are not able to be
| seen by the code within the Trigger.
*/
pragma autonomous_transaction;
n_student_count NUMBER := 0;
BEGIN
IF UPDATING THEN
/* Not sure how you plan to tie the Subjects between each of the two tables
| but I'm guessing this would be a non-issue for you.
*/
UPDATE student_score_table SET subject_a = NULL
WHERE student_id = :old.student_id
;
COMMIT;
dbms_output.put_line('This student_id was UPDATED: ' || :old.student_id || ' for subject_id: ' || :old.subject_id);
END IF;
IF DELETING THEN
SELECT COUNT(student_id)
INTO n_student_count
FROM score_table
WHERE student_id = :old.student_id
;
dbms_output.put_line(n_student_count);
IF n_student_count <= 1 THEN
DELETE student_score_table
WHERE student_id = :old.student_id
;
COMMIT;
dbms_output.put_line('This student_id was DELETED: ' || :old.student_id);
END IF;
END IF;
exception
when others then
raise;
END;
See it in Action
我有两个 table。由于我无法共享 table 的名称,因为它太具体了,我将尝试使用通用 tables.
来解释我的查询两个table是Score_table;它存储学生的分数,让我们说另一个 table 是一个分数仪表板 (Student_Score_Table),它提供了一个视图分数。
Score_table
|------------|------------|-------|
| Student ID | Subject ID | Score |
|------------|------------|-------|
| 12 | 1 | 50 |
|------------|------------|-------|
| 12 | 2 | 70 |
Student_Score_Table
|--------------|------------|----------|
| Student Name | Subject A | Subject B|
|--------------|------------|----------|
| Daniel | 50 | 90 |
|--------------|------------|----------|
| James | 70 | 45 |
学生和科目有各自的查找 tables 从那里我得到学生姓名和科目。
有一项服务可以更新和删除 Score_table
我在考虑如何编写删除时遇到问题 trigger.How 我可以在这里编写一个触发器吗:-
1. 删除分数 Student_Score_Table
即当我更新 Score_table
中的值时将其设置为空
2. 当从 Score_table
Student_Score_Table
中的整个记录
我尝试在 Score_table
上触发后写一个删除,并在使用计数查询删除 Student_Score_Table
之前检查学生是否有任何记录,但我得到的结果是“1”计数为“0”。
虽然不能 100% 确定您需要什么,但我能够使用此触发器完成我认为您正在寻求完成的事情:
CREATE OR REPLACE TRIGGER student_score_trig
AFTER
DELETE OR UPDATE of score
ON score_table
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
DELETE student_score_table
WHERE student_id = :old.student_id
;
exception
when others then
raise;
END;
Full Setup below... creating tables... inserting data and compiling trigger is all below:
CREATE TABLE score_table
( student_id NUMBER,
subject_id NUMBER,
score NUMBER
)
;
/
INSERT INTO score_table VALUES (12, 1, 50);
INSERT INTO score_table VALUES (12, 2, 70);
INSERT INTO score_table VALUES (10, 5, 60);
/
CREATE TABLE student_score_table
( student_id NUMBER,
student_name VARCHAR2(250),
subject_a NUMBER,
subject_b NUMBER
)
;
INSERT INTO student_score_table VALUES (12, 'Daniel', 50, 90);
INSERT INTO student_score_table VALUES (10, 'James', 70, 45);
/
set define off; /* Depending on your interface this line might need to be removed */
CREATE OR REPLACE TRIGGER student_score_trig
AFTER
DELETE OR UPDATE of score
ON score_table
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
DELETE student_score_table
WHERE student_id = :old.student_id
;
exception
when others then
raise;
END;
See it in Action
我不会使用单独的 table 和触发器,而是使用简单的数据透视查询:
select *
from (
select subject_name, student_name, score
from score
join students using (student_id)
join subjects using (subject_id))
pivot (max(score) for subject_name in ('Subject A', 'Subject B'))
制作一个视图,用它代替 table student_subject_score
并忘记与同步相关的触发器和问题。
您当前的解决方案使事情变得复杂。您可以在 score
上触发,但检查特定学生是否存在任何行也需要 select
在 table 分数上。这在 row-level 触发器上是不允许的,会导致 mutating table
错误。要解决这个问题,您可能需要复合触发器。此外,您的设计需要复杂的 case when
(因为我们必须找到要取消的列),或者动态的 SQL。干什么,老了,简单可靠view
解决了所有问题?
见下方更新的触发代码。与我对该问题的上次回答相比,我对触发器应用的更新确实带有一些警告。请参阅 THIS SO Post 以了解这些问题:
触发码
create or replace TRIGGER student_score_trig
AFTER
DELETE OR UPDATE of score
ON score_table
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
/* The below pragma allows us to SELECT from the same table that Triggered the Trigger.
| Many circles say that doing any 'work' on the same table as the Trigger
| is dangerous due to possible uncommited changes that are not able to be
| seen by the code within the Trigger.
*/
pragma autonomous_transaction;
n_student_count NUMBER := 0;
BEGIN
IF UPDATING THEN
/* Not sure how you plan to tie the Subjects between each of the two tables
| but I'm guessing this would be a non-issue for you.
*/
UPDATE student_score_table SET subject_a = NULL
WHERE student_id = :old.student_id
;
COMMIT;
dbms_output.put_line('This student_id was UPDATED: ' || :old.student_id || ' for subject_id: ' || :old.subject_id);
END IF;
IF DELETING THEN
SELECT COUNT(student_id)
INTO n_student_count
FROM score_table
WHERE student_id = :old.student_id
;
dbms_output.put_line(n_student_count);
IF n_student_count <= 1 THEN
DELETE student_score_table
WHERE student_id = :old.student_id
;
COMMIT;
dbms_output.put_line('This student_id was DELETED: ' || :old.student_id);
END IF;
END IF;
exception
when others then
raise;
END;
Full Setup below... creating tables... inserting data and compiling trigger is all below:
CREATE TABLE score_table
( student_id NUMBER,
subject_id NUMBER,
score NUMBER
)
;
/
INSERT INTO score_table VALUES (12, 1, 50);
INSERT INTO score_table VALUES (12, 2, 70);
INSERT INTO score_table VALUES (10, 5, 60);
/
CREATE TABLE student_score_table
( student_id NUMBER,
student_name VARCHAR2(250),
subject_a NUMBER,
subject_b NUMBER
)
;
INSERT INTO student_score_table VALUES (12, 'Daniel', 50, 90);
INSERT INTO student_score_table VALUES (10, 'James', 70, 45);
/
--set define off; /* Depending on your interface this line might need to be removed */
--/
create or replace TRIGGER student_score_trig
AFTER
DELETE OR UPDATE of score
ON score_table
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
/* The below pragma allows us to SELECT from the same table that Triggered the Trigger.
| Many circles say that doing any 'work' on the same table as the Trigger
| is dangerous due to possible uncommited changes that are not able to be
| seen by the code within the Trigger.
*/
pragma autonomous_transaction;
n_student_count NUMBER := 0;
BEGIN
IF UPDATING THEN
/* Not sure how you plan to tie the Subjects between each of the two tables
| but I'm guessing this would be a non-issue for you.
*/
UPDATE student_score_table SET subject_a = NULL
WHERE student_id = :old.student_id
;
COMMIT;
dbms_output.put_line('This student_id was UPDATED: ' || :old.student_id || ' for subject_id: ' || :old.subject_id);
END IF;
IF DELETING THEN
SELECT COUNT(student_id)
INTO n_student_count
FROM score_table
WHERE student_id = :old.student_id
;
dbms_output.put_line(n_student_count);
IF n_student_count <= 1 THEN
DELETE student_score_table
WHERE student_id = :old.student_id
;
COMMIT;
dbms_output.put_line('This student_id was DELETED: ' || :old.student_id);
END IF;
END IF;
exception
when others then
raise;
END;
See it in Action