SQL 查看触发器
SQL Trigger for View
我有一个名为 Absence 的 table,它记录了员工缺勤的时间
CREATE TABLE Absence
(
absence_id_pk varchar(6) NOT NULL,
staff_id_fk varchar(6),
start_date date,
end_date date,
reason varchar(30),
PRIMARY KEY (absence_id_pk),
FOREIGN KEY (staff_id_fk) REFERENCES Full_Time_Employee(staff_id_fk)
);
我创建了一个视图来计算员工缺勤的总天数,如下所示:
CREATE VIEW employee_absence
AS
SELECT staff_id_pk,
staff.first_name,
staff.last_name,
SUM(end_date -start_date) AS "Total Days Absent"
FROM Staff, Absence
WHERE Absence.staff_id_fk = Staff.staff_id_pk
GROUP BY staff_id_pk, staff.first_name, staff.last_name
ORDER BY staff_id_pk;
我是触发器的新手,我想要的是一个触发器,当员工缺勤的总天数 > 20 天时,它会在屏幕上打印一条消息。作为触发器的新手,我不知道如何去做。
任何帮助或想法将不胜感激!
您可以通过以下两种方式之一完成:
- 检查基础上的约束 table。
- 基地触发table
我会选择检查约束而不是触发器,如果员工缺勤超过 20 天,我将不允许员工在 table 中输入记录。
检查约束
SQL> DROP TABLE absence PURGE;
Table dropped.
SQL>
SQL> CREATE TABLE Absence
2 (
3 absence_id_pk varchar(6) NOT NULL,
4 staff_id_fk varchar(6),
5 start_date date,
6 end_date date,
7 reason varchar(30),
8 PRIMARY KEY (absence_id_pk)
9 );
Table created.
SQL>
SQL> ALTER TABLE Absence ADD CONSTRAINT chk CHECK(end_date - start_date <= 20);
Table altered.
SQL>
SQL> INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(1, SYSDATE -20, SYSDATE);
1 row created.
SQL> INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(2, SYSDATE -21, SYSDATE);
INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(2, SYSDATE -21, SYSDATE)
*
ERROR at line 1:
ORA-02290: check constraint (LALIT.CHK) violated
SQL>
触发方法
SQL> DROP TABLE absence PURGE;
Table dropped.
SQL>
SQL> CREATE TABLE Absence
2 (
3 absence_id_pk varchar(6) NOT NULL,
4 staff_id_fk varchar(6),
5 start_date date,
6 end_date date,
7 reason varchar(30),
8 PRIMARY KEY (absence_id_pk)
9 );
Table created.
SQL> CREATE OR REPLACE TRIGGER trg
2 BEFORE INSERT
3 ON absence
4 FOR EACH ROW
5 BEGIN
6 IF :NEW.end_date - :NEW.start_date > 20
7 THEN
8 RAISE_APPLICATION_ERROR(-20001, 'Total days absent are more than 20');
9 END IF;
10 END;
11 /
Trigger created.
SQL>
SQL> INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(1, SYSDATE -20, SYSDATE);
1 row created.
SQL> INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(2, SYSDATE -21, SYSDATE);
INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(2, SYSDATE -21, SYSDATE)
*
ERROR at line 1:
ORA-20001: Total days absent are more than 20
ORA-06512: at "LALIT.TRG", line 4
ORA-04088: error during execution of trigger 'LALIT.TRG'
SQL>
如果您仍要允许插入,则只显示消息。然后,删除 RAISE_APPLICATION_ERROR 并改用 DBMS_OUTPUT。
SQL> DROP TABLE absence PURGE;
Table dropped.
SQL>
SQL> CREATE TABLE Absence
2 (
3 absence_id_pk varchar(6) NOT NULL,
4 staff_id_fk varchar(6),
5 start_date date,
6 end_date date,
7 reason varchar(30),
8 PRIMARY KEY (absence_id_pk)
9 );
Table created.
SQL> CREATE OR REPLACE TRIGGER trg
2 BEFORE INSERT
3 ON absence
4 FOR EACH ROW
5 BEGIN
6 IF :NEW.end_date - :NEW.start_date > 20
7 THEN
8 DBMS_OUTPUT.PUT_LINE('Total days absent are more than 20');
9 END IF;
10 END;
11 /
Trigger created.
SQL>
SQL> INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(1, SYSDATE -20, SYSDATE);
1 row created.
SQL> INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(2, SYSDATE -21, SYSDATE);
Total days absent are more than 20
1 row created.
SQL>
您的解决方案存在几个问题。
- 切勿在触发器中使用 DBMS_OUTPUT。当您编写它并从您的 IDE 进行测试时,这可能会正常工作,但它通常不会导致任何消息传到任何应用程序。触发器写入日志 tables.
- 您的视图触发器只会在问题发生 之后的下一次插入时捕获问题。这可能是几天或几个月之后,缺勤人数可能 比 20 多。
- 确实没有理由对视图执行插入操作。您不能使用该视图插入新的缺席,因为该视图不公开日期。还是您执行 INSERT 只是为了检查缺席天数?在那种情况下,您为什么不直接从 days > 20 的视图中查询?
您最好的做法是让 table 本身的插入和更新后触发器检查缺席天数,如果天数 > 20,则写入日志条目。此日志条目可以包含任何触发器可以获得的信息:如果操作是 Insert 或 Update,则影响的员工、执行操作的用户、执行操作的日期和时间、操作生效前缺席的天数、手术生效后缺席天数等。
计划的作业可以检查日志 table 并在遇到新条目时执行某些操作(发送电子邮件等)。
我有一个名为 Absence 的 table,它记录了员工缺勤的时间
CREATE TABLE Absence
(
absence_id_pk varchar(6) NOT NULL,
staff_id_fk varchar(6),
start_date date,
end_date date,
reason varchar(30),
PRIMARY KEY (absence_id_pk),
FOREIGN KEY (staff_id_fk) REFERENCES Full_Time_Employee(staff_id_fk)
);
我创建了一个视图来计算员工缺勤的总天数,如下所示:
CREATE VIEW employee_absence
AS
SELECT staff_id_pk,
staff.first_name,
staff.last_name,
SUM(end_date -start_date) AS "Total Days Absent"
FROM Staff, Absence
WHERE Absence.staff_id_fk = Staff.staff_id_pk
GROUP BY staff_id_pk, staff.first_name, staff.last_name
ORDER BY staff_id_pk;
我是触发器的新手,我想要的是一个触发器,当员工缺勤的总天数 > 20 天时,它会在屏幕上打印一条消息。作为触发器的新手,我不知道如何去做。
任何帮助或想法将不胜感激!
您可以通过以下两种方式之一完成:
- 检查基础上的约束 table。
- 基地触发table
我会选择检查约束而不是触发器,如果员工缺勤超过 20 天,我将不允许员工在 table 中输入记录。
检查约束
SQL> DROP TABLE absence PURGE;
Table dropped.
SQL>
SQL> CREATE TABLE Absence
2 (
3 absence_id_pk varchar(6) NOT NULL,
4 staff_id_fk varchar(6),
5 start_date date,
6 end_date date,
7 reason varchar(30),
8 PRIMARY KEY (absence_id_pk)
9 );
Table created.
SQL>
SQL> ALTER TABLE Absence ADD CONSTRAINT chk CHECK(end_date - start_date <= 20);
Table altered.
SQL>
SQL> INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(1, SYSDATE -20, SYSDATE);
1 row created.
SQL> INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(2, SYSDATE -21, SYSDATE);
INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(2, SYSDATE -21, SYSDATE)
*
ERROR at line 1:
ORA-02290: check constraint (LALIT.CHK) violated
SQL>
触发方法
SQL> DROP TABLE absence PURGE;
Table dropped.
SQL>
SQL> CREATE TABLE Absence
2 (
3 absence_id_pk varchar(6) NOT NULL,
4 staff_id_fk varchar(6),
5 start_date date,
6 end_date date,
7 reason varchar(30),
8 PRIMARY KEY (absence_id_pk)
9 );
Table created.
SQL> CREATE OR REPLACE TRIGGER trg
2 BEFORE INSERT
3 ON absence
4 FOR EACH ROW
5 BEGIN
6 IF :NEW.end_date - :NEW.start_date > 20
7 THEN
8 RAISE_APPLICATION_ERROR(-20001, 'Total days absent are more than 20');
9 END IF;
10 END;
11 /
Trigger created.
SQL>
SQL> INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(1, SYSDATE -20, SYSDATE);
1 row created.
SQL> INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(2, SYSDATE -21, SYSDATE);
INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(2, SYSDATE -21, SYSDATE)
*
ERROR at line 1:
ORA-20001: Total days absent are more than 20
ORA-06512: at "LALIT.TRG", line 4
ORA-04088: error during execution of trigger 'LALIT.TRG'
SQL>
如果您仍要允许插入,则只显示消息。然后,删除 RAISE_APPLICATION_ERROR 并改用 DBMS_OUTPUT。
SQL> DROP TABLE absence PURGE;
Table dropped.
SQL>
SQL> CREATE TABLE Absence
2 (
3 absence_id_pk varchar(6) NOT NULL,
4 staff_id_fk varchar(6),
5 start_date date,
6 end_date date,
7 reason varchar(30),
8 PRIMARY KEY (absence_id_pk)
9 );
Table created.
SQL> CREATE OR REPLACE TRIGGER trg
2 BEFORE INSERT
3 ON absence
4 FOR EACH ROW
5 BEGIN
6 IF :NEW.end_date - :NEW.start_date > 20
7 THEN
8 DBMS_OUTPUT.PUT_LINE('Total days absent are more than 20');
9 END IF;
10 END;
11 /
Trigger created.
SQL>
SQL> INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(1, SYSDATE -20, SYSDATE);
1 row created.
SQL> INSERT INTO absence(absence_id_pk, start_date, end_date) VALUES(2, SYSDATE -21, SYSDATE);
Total days absent are more than 20
1 row created.
SQL>
您的解决方案存在几个问题。
- 切勿在触发器中使用 DBMS_OUTPUT。当您编写它并从您的 IDE 进行测试时,这可能会正常工作,但它通常不会导致任何消息传到任何应用程序。触发器写入日志 tables.
- 您的视图触发器只会在问题发生 之后的下一次插入时捕获问题。这可能是几天或几个月之后,缺勤人数可能 比 20 多。
- 确实没有理由对视图执行插入操作。您不能使用该视图插入新的缺席,因为该视图不公开日期。还是您执行 INSERT 只是为了检查缺席天数?在那种情况下,您为什么不直接从 days > 20 的视图中查询?
您最好的做法是让 table 本身的插入和更新后触发器检查缺席天数,如果天数 > 20,则写入日志条目。此日志条目可以包含任何触发器可以获得的信息:如果操作是 Insert 或 Update,则影响的员工、执行操作的用户、执行操作的日期和时间、操作生效前缺席的天数、手术生效后缺席天数等。
计划的作业可以检查日志 table 并在遇到新条目时执行某些操作(发送电子邮件等)。