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