Oracle的儲存過程
一、什麼是儲存過程?
儲存過程就是一組為了完成特定功能的SQL語句集,儲存在資料庫中;這樣經過第一次編譯後再次呼叫不需要再次編譯,直接呼叫或者通過java掉用(就是個SQL語句集)
在Oracle中儲存過程是procedure
優勢:
1. 相比普通的sql語句,每次都要先編譯在執行,相對而言儲存過程效率更高
2. 降低網路流量(儲存過程編譯好後直接存在資料庫中,遠端呼叫時,不會傳輸大量的字串型別的sql語句)
3. 複用性高:一次編譯後,以後直接呼叫
4. 可維護性更高:修改比較容易
5. 安全性高:可以指定使用者進行儲存過程的呼叫
二、儲存過程的建立方式:
2.1 無參
CREATE OR REPLACE PROCEDURE 儲存過程名稱
AS/IS
變數2 DATE;
變數3 NUMBER;
BEGIN
--要處理的業務邏輯
EXCEPTION --儲存過程異常(可寫可不寫)
END
2.2 有參
2.2.1 帶引數的儲存過程(輸入引數:id ; 輸出引數:name)
1 CREATE OR REPLACE PROCEDURE 儲存過程名稱(param1 student.id%TYPE) 2 AS/IS 3 name student.name%TYPE; 4 age number :=20; 5 BEGIN 6 --業務處理..... 7 END
上面指令碼中,
第1行:param1 是引數,型別和student表id欄位的型別一樣。
第3行:宣告變數name,型別是student表name欄位的型別(同上)。
第4行:宣告變數age,型別數數字,初始化為20
2.2.2 帶引數的儲存過程並且進行賦值
1 CREATE OR REPLACE PROCEDURE 儲存過程名稱( 2 s_no in varchar, 3 s_name out varchar, 4 s_age number) AS 5 total NUMBER := 0; 6 BEGIN 7 SELECT COUNT(1) INTO total FROM student s WHERE s.age=s_age; 8 dbms_output.put_line('符合該年齡的學生有'||total||'人'); 9 EXCEPTION 10 WHEN too_many_rows THEN 11 DBMS_OUTPUT.PUT_LINE('返回值多於1行'); 12 END
上面指令碼中:
其中引數IN表示輸入引數,是引數的預設模式。
OUT表示返回值引數,型別可以使用任意Oracle中的合法型別。
OUT模式定義的引數只能在過程體內部賦值,表示該引數可以將某個值傳遞迴呼叫他的過程
IN OUT表示該引數可以向該過程中傳遞值,也可以將某個值傳出去
第7行:查詢語句,把引數s_age作為過濾條件,INTO關鍵字,把查到的結果賦給total變數。
第8行:輸出查詢結果,在資料庫中“||”用來連線字串
第9—11行:做異常處理
三、儲存過程的語法
3.1 將結果放入一個或多個變數中:
1 CREATE OR REPLACE PROCEDURE DEMO_CDD1 IS
2 s_name VARCHAR2; --學生名稱
3 s_age NUMBER; --學生年齡
4 s_address VARCHAR2; --學生籍貫
5 BEGIN
6 --給單個變數賦值
7 SELECT student_address INTO s_address
8 FROM student where student_grade=100;
9 --給多個變數賦值
10 SELECT student_name,student_age INTO s_name,s_age
11 FROM student where student_grade=100;
12 --輸出成績為100分的那個學生資訊
13 dbms_output.put_line('姓名:'||s_name||',年齡:'||s_age||',籍貫:'||s_address);
14 END
3.2 選擇語句:
IF s_sex=1 THEN
dbms_output.put_line('這個學生是男生');
END IF
IF s_sex=1 THEN
dbms_output.put_line('這個學生是男生');
ELSE
dbms_output.put_line('這個學生是女生');
END IF
3.3 迴圈語句
1 -- 基本迴圈
2 LOOP
3 IF 表示式 THEN
4 EXIT;
5 END IF
6 END LOOP;
7
8 -- while迴圈
9 WHILE 表示式 LOOP
10 dbms_output.put_line('haha');
11 END LOOP;
12
13 -- for迴圈
14 FOR a in 10 .. 20 LOOP
15 dbms_output.put_line('value of a: ' || a);
16 END LOOP;
練習:
有表student(s_no, s_name, s_age, s_grade),其中s_no-學號,也是主鍵,是從1開始向上排的(例如:第一個學生學號是1,第二個是2,一次類推);s_name-學生姓名;s_age-學生年齡;s_grade-年級;這張表的資料量有幾千萬甚至上億。一個學年結束了,我要讓這些學生全部升一年級,即,讓s_grade欄位加1。
這條sql,寫出來如下:
update student set s_grade=s_grade+1
分析:
如果我們直接執行執行這條sql,因資料量太大會把資料庫undo表空間撐爆,從而發生異常。那我們來寫個儲存過程,進行批量更新,我們每10萬條提交一次。
CREATE OR REPLACE PROCEDURE process_student is total NUMBER := 0; i NUMBER := 0; BEGIN SELECT COUNT(1) INTO total FROM student; WHILE i<=total LOOP UPDATE student SET grade=grade+1 WHERE s_no=i; i := i + 1; IF i >= 100000 THEN COMMIT; END IF; END LOOP; dbms_output.put_line('finished!'); END;