PL / SQL Trigger для расчета общей посещаемости - PullRequest
0 голосов
/ 04 мая 2018

Я хочу создать триггер для расчета общей посещаемости для каждой отдельной записи из данной таблицы.

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 голосов
/ 04 мая 2018

Я бы порекомендовал вам не злоупотреблять a 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
0 голосов
/ 05 мая 2018

Я бы предложил использовать этот набор из 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. Я в основном игнорировал столбцы SUBJECT и DATE_ATT, поскольку, судя по вопросу, они не влияют на цель.

Вспомогательный триггер может быть сброшен, если вам не нужно обрабатывать удаления из таблицы DAILY_ATT или он может содержать ноль записей в таблице TOTAL_ATT для вещей, полностью удаленных из DAILY_ATT.

Для повышения производительности проверку на изменение ROLL_NO следует перенести в отдельный триггер BEFORE UPDATE. Вспомогательный триггер обычно получает большую выгоду от индекса на ROLL_NO в таблице DAILY_ATT.

Вот для этого SQL-скрипта.

0 голосов
/ 04 мая 2018

Надеюсь, что это послужит вашей цели

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...