Oracle存儲過程與觸發器


7-1(存儲過程)創建一個顯示學生總人數的存儲過程

 1 SQL>SET SERVEROUTPUT  ON
 2 SQL>CREATE  OR REPLACE PROCEDURE STU_COUNT
 3   2AS           --需要定義的存儲過程內的變量均寫在AS下
 4    3TOTAL    NUMBER --定義
 5    4BEGIN
 6    5     SELECT COUNT(SNO) INTO TOTAL FROM STUDENT; --SELECT 后的變量個數要與INTO 后一致
 7    6     DBMS_OUTPUT.PUT_LINE('總數:'||TOTAL);  --字符'||'的含義是連接兩個字符串
 8    7END;
 9    8/
10 
11 SQL>EXECUTE STU_COUNT;
總數:12

PL/SQL 過程已成功完成。

 

7-2(存儲過程)創建顯示學生信息的存儲過程STUDENT_LIST,並引用STU_COUNT存儲過程

 1 SQL> SET SERVEROUTPUT ON
 2 SQL> CREATE OR REPLACE PROCEDURE STUDENT_LIST
 3   2  AS
 4   3  SNO                STUDENT.SNO%TYPE;
 5   4  SNAME      STUDENT.SNAME%TYPE;
 6   5  CURSOR C_STUDENT_INFO IS SELECT SNO,SNAME FROM STUDENT;
 7   6  BEGIN
 8   7     FOR C_STUDENT_i IN C_STUDENT_INFO
 9   8     LOOP
10   9     DBMS_OUTPUT.PUT_LINE(C_STUDENT_i.SNO||'---'||C_STUDENT_i.SNAME);
11  10     END LOOP;
12  11     STU_COUNT();
13  12  END;
14  13  /
15 
16 過程已創建。

運行結果

SQL> EXECUTE STUDENT_LIST;
96001---馬小燕
96002---黎明
96003---劉東明
96004---趙志勇
97001---馬蓉
97002---李成功
97003---黎明
97004---李麗
74313---錢常來
96006---張然
96005---司馬志明
20001---趙薇
總數:12

PL/SQL 過程已成功完成。

如果寫存儲過程總是會報錯,可以先測試一下游標環節是否有問題,游標測試編寫如下:

SQL> DECLARE
  2  SNO        STUDENT.SNO%TYPE;
  3  SNAME      STUDENT.SNAME%TYPE;
  4  CURSOR C_STUDENT_INFO IS SELECT SNO,SNAME FROM STUDENT;
  5  BEGIN
  6     FOR C_STUDENT_i IN C_STUDENT_INFO
  7     LOOP
  8     DBMS_OUTPUT.PUT_LINE(C_STUDENT_i.SNO||'---'||C_STUDENT_i.SNAME);
  9     END LOOP;
 10  END;
 11  /
96001---馬小燕
96002---黎明
96003---劉東明
96004---趙志勇
97001---馬蓉
97002---李成功
97003---黎明
97004---李麗
74313---錢常來
96006---張然
96005---司馬志明
20001---趙薇

PL/SQL 過程已成功完成。

 

7-3(存儲過程)創建一個顯示學生平均成績的存儲過程

 1 SQL> SET SERVEROUTPUT ON;
 2 SQL> CREATE OR REPLACE PROCEDURE AVGSCORE(NO IN STUDENT.SNO%TYPE)
 3   2  AS
 4   3  AVERAGE NUMBER(5,2);
 5   4  BEGIN
 6   5     SELECT AVG(SCORE)INTO AVERAGE FROM SCORE GROUP BY SNO HAVING SNO = NO;
 7   6     DBMS_OUTPUT.PUT_LINE(NO||'---'||AVERAGE);
 8   7  END;
 9   8  /
10 SQL> EXECUTE AVGSCORE('96001');
11 96001---83.63
12 
13 PL/SQL 過程已成功完成。

7-4  (存儲過程)  創建顯示所有學生平均成績的存儲過程

 1 SQL> SET SERVEROUTPUT ON
 2 SQL> CREATE OR REPLACE PROCEDURE STUDENT_AVG
 3   2  AS
 4   3  CURSOR SCORE_AVG IS SELECT SNO,AVG(SCORE) AS AVG_SCORE FROM SCORE GROUP BY SNO;
 5   4  BEGIN
 6   5     FOR I IN SCORE_AVG
 7   6     LOOP
 8   7             DBMS_OUTPUT.PUT_LINE(I.SNO||'---'||I.AVG_SCORE);
 9   8     END LOOP;
10   9  END;
11  10  /
12 
13 過程已創建。
14 
15 SQL> EXECUTE STUDENT_AVG;
16 74313---72
17 96001---83.625
18 96002---90.16666666666666666666666666666666666667
19 96003---80
20 96004---87
21 96005---86.75
22 97001---95.5
23 97002---91.5
24 97003---58.5
25 97004---83.33333333333333333333333333333333333333
26 
27 PL/SQL 過程已成功完成。

--如何讓輸出數據格式一致??
SQL> DECLARE
  2  SNO                SCORE.SNO%TYPE;
  3  AVG_SCORE          SCORE.SCORE%TYPE;
  4  CURSOR STUDENT_AVG IS SELECT AVG(SCORE) INTO AVG_SCORE FROM SCORE GROUP BY SNO;
  5  BEGIN
  6     FOR I IN STUDENT_AVG
  7     LOOP
  8             DBMS_OUTPUT.PUT_LINE(I.SNO||'---'||I.AVG_SCORE);
  9     END LOOP;
 10  END;
 11  /
                DBMS_OUTPUT.PUT_LINE(I.SNO||'---'||I.AVG_SCORE);
                                       *
第 8 行出現錯誤:
ORA-06550: 第 8 行, 第 26 列:
PLS-00302: 必須聲明 'SNO' 組件
ORA-06550: 第 8 行, 第 3 列:
PL/SQL: Statement ignored

這是什么錯?

7-5(修改數據庫)在STUDENT表中增加SAVG(N,6,2)字段

1 SQL> ALTER TABLE STUDENT ADD SAVG NUMBER(6,2);
2 
3 表已更改。

 

7-6(存儲過程)創建存儲過程,計算每個學生的平均成績保存到學生表中SAVG字段中

 1 SQL> SET SERVEROUTPUT ON
 2 SQL> CREATE OR REPLACE PROCEDURE SAVE_SAVG
 3   2  AS
 4   3  CURSOR STUDENT_AVG IS SELECT SNO,AVG(SCORE) AS AG FROM SCORE GROUP BY SNO;
 5   4  BEGIN
 6   5     FOR I IN STUDENT_AVG
 7   6             LOOP
 8   7             UPDATE STUDENT SET SAVG = I.AG WHERE SNO = I.SNO;
 9   8     END LOOP;
10   9  END;
11  10  /
12 
13 過程已創建。
14 
15 SQL> EXECUTE SAVE_SAVG;
16 
17 PL/SQL 過程已成功完成。
18 
19 SQL> SELECT * FROM STUDENT;
20 
21 SNO        SNAME                    SDEP SCLA SSEX         SAGE       SAVG
22 ---------- ------------------------ ---- ---- ------ ---------- ----------
23 96001      馬小燕                   CS   01   女             22      83.63
24 96002      黎明                     CS   01   男             19      90.17
25 96003      劉東明                   MA   01   男             18         80
26 96004      趙志勇                   IS   02   男             20         87
27 97001      馬蓉                     MA   02   女             19       95.5
28 97002      李成功                   CS   01   男             21       91.5
29 97003      黎明                     IS   03   女             19       58.5
30 97004      李麗                     CS   02   女             20      83.33
31 74313      錢常來                   SC   02   女             19         72
32 96006      張然                     CS   02   男             20
33 96005      司馬志明                 CS   02   男             19      86.75
34 
35 SNO        SNAME                    SDEP SCLA SSEX         SAGE       SAVG
36 ---------- ------------------------ ---- ---- ------ ---------- ----------
37 20001      趙薇                     IS   02   女             19
38 
39 已選擇12行

 

7-7  (觸發器)  當更新學生成績表SCORE 中的學生成績時,自動計算該學生的平均成績保存到學生表中SAVG字段中

 

SQL>CREATE OR REPLACE PACKAGE MY_PACK    
        AS
        a    STUDENT.SNO%TYPE;
        END;
        /

SQL>CREATE OR REPLACE TRIGGER UPD_SC
        BEFORE UPDATE ON SCORE
        REFERENCING NEW AS NEW OLD AS OLD
        FOR EACH ROW
        BEGIN
            MY_PACK.a := :NEW.SNO;
        END;
        /

SQL>CREATE OR REPLACE TRIGGER UPD_SC_1
        AFTER UPDATE ON SCRE
        REFERENCING NEW AS NEW OLD AS OLD
        FOR EACH ROW
        DECLARE
        b    SCORE.SCORE%TYPE;
        PRAGMA AUTONOMOUS TRANSATION;
        BEGIN
            IF UPDATING    THEN
                SELECT AVG(SCORE) INTO b FROM SCORE WHERE SNO = MY_PACK.a  GROUP BY SNO;
            UPDATE STUDENT SET SAVG=b WHERE SNO= MY_PACK.a;
            END IF ;
        COMMIT;
        END;
        /

 

7-8 (觸發器) 創建包含插入、刪除、修改多種觸發事件的觸發器DBM_LOG,對SCORE表的操作進行記錄。用INSETING、DELETING、UPDATING謂詞來區別不同的DML操作

先創建事件記錄表LOGS,該表用來對操作進行記錄。該表的字段含義解釋如下:

    LOG_ID:操作記錄的編號,數值型,它是該表的主鍵,自動增1,可由序列自動生成。

    LOG_TABLE:進行操作的表名,字符型,非空,該表設計成可以由多個觸發器共享使用。比如我們可以為Student表創建類似的觸發器,同樣將操作記錄到該表。

    LOG_DML:操作的動作,即INSERT、DELETE或UPDATE三種之一。

    LOG_KEY_ID:操作時表的主鍵值,數值型。之所以記錄表的主鍵,是因為主鍵是表的記錄的惟一標識,可以識別是對哪一條記錄進行了操作。對於Score表,主鍵是由SNO_CNO構成。

    LOG_DATE:操作的日期,日期型,取當前的系統時間。

    LOG_USER:操作者,字符型,取當時的操作者賬戶名。比如登錄SCOTT賬戶進行操作,在該字段中,記錄賬戶名為SCOTT。

CREATE TABLE LOGS
(
    LOG_ID    NUMBER(10) PRIMARY KEY,
    LOG_TABLE    VARCHAR2(10) NOT NULL,
    LOG_DML        VARCHAR2(10),
    LOG_KEY_ID    NUMBER(10),
    LOG_DATE    DATE,
    LOG_USER     VARCHAR2(15)
);
CREATE SEQUENCE LOGS_ID_SQU 
INCREMENT BY 1
START WITH 1
MAXVALUE 99999
NOCYCLE NOCACHE;

 

SQL> CREATE OR REPLACE TRIGGER DML_LOG
  2  BEFORE
  3  DELETE OR INSERT OR UPDATE ON SCORE
  4  REFERENCING NEW AS NEW OLD AS OLD
  5  FOR EACH ROW
  6  BEGIN
  7     IF INSERTING THEN
  8             INSERT INTO LOGS VALUES(LOGS_ID_SQU.NEXTVAL,'SCORE','INSERT',:NEW.SCORE,SYSDATE,USER);
  9     ELSIF DELETING THEN
 10             INSERT INTO LOGS VALUES(LOGS_ID_SQU.NEXTVAL,'SCORE','DELETE',:NEW.SCORE,SYSDATE,USER);
 11     ELSIF UPDATING THEN
 12             INSERT INTO LOGS VALUES(LOGS_ID_SQU.NEXTVAL,'SCORE','UPDATE',:NEW.SCORE,SYSDATE,USER);
 13     END IF ;
 14  END;
 15  /

觸發器已創建

SQL> INSERT INTO SCORE VALUES('96001','002',83);

已創建 1 行。

SQL> select * from logs;

    LOG_ID LOG_TABLE                                LOG_DML                                  LOG_KEY_ID LOG_DATE       LOG_USER
---------- ---------------------------------------- ---------------------------------------- ---------- -------------- ----------------------------------------
1 SCORE INSERT 83 18-6月 -18 SYSTEM

LOG_KEY_ID:操作時表的主鍵值,數值型,對於Score表,主鍵是由SNO_CNO構成。 ?????

 

SQL> SELECT * FROM SCORE WHERE SNO='96001';

SNO        CNO         SCORE
---------- ------ ----------
96001      001            90
96001      002            83
96001      003            92
96001      004            92
96001      005            92

SQL> UPDATE SCORE SET SCORE = 97 WHERE SNO = '96001' AND CNO= '003';

已更新 1 行。

SQL> DELETE FROM SCORE WHERE SNO='96001' AND CNO='005';

已刪除 1 行。

SQL> SELECT * FROM LOGS;

    LOG_ID LOG_TABLE
---------- ----------------------------------------
LOG_DML                                  LOG_KEY_ID LOG_DATE
---------------------------------------- ---------- --------------
LOG_USER
----------------------------------------
         1 SCORE
INSERT                                           83 18-6月 -18
SYSTEM

         2 SCORE
UPDATE                                           97 18-6月 -18
SYSTEM

    LOG_ID LOG_TABLE
---------- ----------------------------------------
LOG_DML                                  LOG_KEY_ID LOG_DATE
---------------------------------------- ---------- --------------
LOG_USER
----------------------------------------

         3 SCORE
DELETE                                              18-6月 -18
SYSTEM

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM