PL / SQL触发器计算总出勤率

时间:2018-05-04 17:07:56

标签: oracle plsql

我想创建一个触发器来计算给定表中每个不同记录的总出勤率。

DAILY_ATT

enter image description here

第二个表应该生成如下输出:

TOTAL_ATT

enter image description here

这就是我所做的:

CREATE TABLE daily_att 
  ( 
     roll_no    NUMBER(5), 
     subject    VARCHAR2(10), 
     attendance NUMBER(5), 
     date_att   DATE 
  ); 

CREATE TABLE total_att 
  ( 
     roll_no          NUMBER(5) NOT NULL PRIMARY KEY, 
     total_attendance NUMBER(5) 
  ); 

INSERT INTO DAILY_ATT VALUES(1, 'MATHS', 0, '04-MAY-18');

INSERT INTO DAILY_ATT VALUES(1, 'ENG', 1, '04-MAY-18');

INSERT INTO DAILY_ATT VALUES(2, 'MATHS', 1, '04-MAY-18');

INSERT INTO DAILY_ATT VALUES(2, 'ENG', 1, '04-MAY-18');

INSERT INTO DAILY_ATT VALUES(1, 'MATHS', 1, '05-MAY-18');

INSERT INTO DAILY_ATT VALUES(1, 'ENG', 1, '05-MAY-18');

INSERT INTO DAILY_ATT VALUES(2, 'MATHS', 0, '05-MAY-18');

INSERT INTO DAILY_ATT VALUES(2, 'ENG', 0, '05-MAY-18');

SELECT * FROM DAILY_ATT;

CREATE OR replace TRIGGER att 
  AFTER INSERT OR UPDATE ON daily_att 
  FOR EACH ROW 
BEGIN 
    SELECT SUM(attendance) 
    INTO   Total_att(total_attendance) 
    FROM   daily_att 
    WHERE  roll_no = :NEW.roll_no; 
END; 

3 个答案:

答案 0 :(得分:0)

希望这符合您的目的

CREATE OR REPLACE TRIGGER create_subtotal
  AFTER INSERT OR UPDATE OR DELETE ON DAILY_ATTENDANCE
  FOR EACH ROW
DECLARE

V_ROLL_NO NUMBER(8); 
V_TOT_ATTENDANCE NUMBER(4);  

BEGIN
  SELECT ROLL_NO,SUM(ATTENDANCE) 
    INTO V_ROLL_NO,V_TOT_ATTENDANCE  
    FROM DAILY_ATTENDANCE
   WHERE ROLL_NO = :new.ROLL_NO AND DATE_ATT=TRUNC(SYSDATE);

    BEGIN
      update TOTAL_ATTENDANCE 
      set TOTAL_ATTENDANCE= TOT_ATTENDANCE
      where ROLL_NO = V_ROLL_NO;

      if sql%rowcount = 0 then
        -- no rows were updated, so the record does not exist
        insert into TOTAL_ATTENDANCE (ROLL_NO,TOTAL_ATTENDANCE )
        values ( V_ROLL_NO,V_TOT_ATTENDANCE );
      END IF;
    END;
END;

答案 1 :(得分:0)

为了这个目的,我建议你不要滥用 Trigger。只需创建一个视图。

CREATE
    OR replace VIEW total_att AS
SELECT roll_no
    ,SUM(attendance) as total_attendance
FROM daily_att
GROUP BY roll_no;

select * FROM total_attendance;

ROLL_NO TOTAL_ATTENDANCE
1       3
2       2

答案 2 :(得分:0)

我的建议是使用这组2个触发器:

核心问题:

CREATE OR REPLACE TRIGGER create_subtotal
  AFTER UPDATE OF roll_no, attendance OR INSERT OR DELETE ON daily_att
  FOR EACH ROW
DECLARE
  v_roll_no daily_att.roll_no%TYPE;
  v_before  daily_att.attendance%TYPE;
  v_after   daily_att.attendance%TYPE;
  v_diff    daily_att.attendance%TYPE;
BEGIN
  IF UPDATING AND (:NEW.roll_no <> :OLD.roll_no) THEN
    RAISE_APPLICATION_ERROR( -20001, 'Altering ROLL_NO is not allowed!' );
  END IF;

  IF NOT INSERTING THEN
    v_before := :OLD.attendance;
    v_roll_no := :OLD.roll_no;
  ELSE
    v_before := 0;
    v_roll_no := :NEW.roll_no;
  END IF;

  IF NOT DELETING THEN
    v_after := :NEW.attendance;
  ELSE
    v_after := 0;
  END IF;

  v_diff := v_after - v_before;

  IF INSERTING OR (v_diff <> 0) THEN
    UPDATE total_att
       SET total_attendance = total_attendance + v_diff
     WHERE roll_no = v_roll_no;

    IF SQL%ROWCOUNT = 0 THEN
      INSERT INTO total_att (roll_no, total_attendance)
      VALUES (v_roll_no, v_diff);
    END IF;
  END IF;
END;

辅助的一个:

CREATE OR REPLACE TRIGGER delete_subtotal
  AFTER DELETE ON daily_att
BEGIN
  DELETE FROM total_att
   WHERE NOT EXISTS (SELECT 1
                       FROM daily_att d
                      WHERE total_att.roll_no = d.roll_no);
END;

我认为ROLL_NO永远不会NULL,也不应该被更改,ATTENDANCE也永远不会NULL。我基本上忽略了SUBJECTDATE_ATT列,因为问题似乎不会影响目标。

如果您不需要处理来自DAILY_ATT表的删除,或者可以在TOTAL_ATT表中保留零条目,则可以删除辅助触发器,以便完全从DAILY_ATT中删除

为了获得更好的性能,应将ROLL_NO更改检查移至单独的BEFORE UPDATE触发器。辅助触发器通常会从ROLL_NO表中的DAILY_ATT索引中获益很多。

Here's an SQL Fiddle for this.