一、什么是存儲過程?
存儲過程就是一組為了完成特定功能的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;