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 天时,它会在屏幕上打印一条消息。作为触发器的新手,我不知道如何去做。

任何帮助或想法将不胜感激!

您可以通过以下两种方式之一完成:

  1. 检查基础上的约束 table。
  2. 基地触发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 并在遇到新条目时执行某些操作(发送电子邮件等)。