我想创建一个触发器来计算给定表中每个不同记录的总出勤率。
DAILY_ATT
第二个表应该生成如下输出:
TOTAL_ATT
这就是我所做的:
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;
答案 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
。我基本上忽略了SUBJECT
和DATE_ATT
列,因为问题似乎不会影响目标。
如果您不需要处理来自DAILY_ATT
表的删除,或者可以在TOTAL_ATT
表中保留零条目,则可以删除辅助触发器,以便完全从DAILY_ATT
中删除
为了获得更好的性能,应将ROLL_NO
更改检查移至单独的BEFORE UPDATE
触发器。辅助触发器通常会从ROLL_NO
表中的DAILY_ATT
索引中获益很多。