Oracle編程
序
? 任意語言的三個基本結構:順序結構、分支結構、循環結構。任意語言都擁有變量和常量。
PL/SQL
PL/SQL的基本概念
? PL/SQL(Procedure Language/SQL),是Oracle對Sql語言的過程化拓展,是一門語言,可以讓SQL具備邏輯,具有過程處理能力。
基本語法結構
[declare --聲明變量]
begin
[plsql代碼]
[exception --異常處理]
end;
--常見的簡單模式
begin
plsql
end
基本元素
變量
注意事項:
- 變量名 變量類型
- 賦值符號 :=
- declare后邊聲明變量,而變量的賦值在begin和end之間
- 內置存儲函數(過程):DBMS_OUTPUT.PUTLINE()
案例
--變量聲明與賦值
declare --聲明
v_price number(10,2);
v_usenum number;
v_usenum2 number(10,2);
v_money(10,2);
begin
v_price:=2.45;
v_usenum:=9213;
v_usenum2:=round(v_usenum/1000,2);
v_money:=v_price*v_usenum2;
DBMS_OUTPUT.put_line('金額:'||v_money);--內置存儲函數,可以輸出
end;
--第二種賦值方法
declare --聲明
v_price number(10,2);
v_usenum number;
v_usenum2 number(10,2);
v_money(10,2);
v_num0 number;
v_num1 number;
begin
v_price:=2.45;
--語句:select 【數據庫中的列名】 into 變量名稱
select usenum into v_usenum from t_account where year='2012' and monyh='01' and owneruuid=1;
v_usenum:=9213;
v_usenum2:=round(v_usenum/1000,2);
v_money:=v_price*v_usenum2;
end
引用類型
語法格式:表名.列名%type
declare --聲明
v_price number(10,2);
--可以直接查找到表中的值的類型
v_usenum t_account.usenum%type;
v_usenum2 number(10,2);
v_money(10,2);
v_num0 number;
v_num1 number;
begin
v_price:=2.45;
select usenum into v_usenum from t_account where year='2012' and monyh='01' and owneruuid=1;
v_usenum:=9213;
v_usenum2:=round(v_usenum/1000,2);
v_money:=v_price*v_usenum2;
end
記錄類型
語法格式:變量名稱 表名%rowtype
使用時語句:變量名稱 . 列名
declare --聲明
v_price number(10,2);
--可以直接查找到表中的值的類型
v_usenum t_account.usenum%type;
v_usenum2 number(10,2);
v_money(10,2);
v_num0 number;
v_num1 number;
begin
v_price:=2.45;
select usenum into v_usenum from t_account where year='2012' and monyh='01' and owneruuid=1;
v_usenum:=9213;
v_usenum2:=round(v_usenum/1000,2);
v_money:=v_price*v_usenum2;
end
異常
在運行程序時出現的錯誤叫做異常(也叫例外)
- 預定義異常
- 自定義異常
預定義異常共有21個
--語法格式
exception
when 異常類型 then
異常處理邏輯
案例
declare
v_price number(10,2);-- 水費單價
v_usenum T_ACCOUNT.USENUM%type; -- 水費字數
v_usenum2 number(10,3);-- 噸數
v_money number(10,2);-- 金額
begin
v_price:=2.45;-- 水費單價
select usenum into v_usenum from T_ACCOUNT where
owneruuid=1 and year='2012' and month='01';
-- 字數換算為噸數
v_usenum2:= round( v_usenum/1000,3);
-- 計算金額
v_money:=round(v_price*v_usenum2,2);
dbms_output.put_line('單價:'||v_price||'噸
數:'||v_usenum2||'金額:'||v_money);
exception
--只要查到這個異常就會處理
when NO_DATA_FOUND then
dbms_output.put_line('未找到數據,請核實');
when TOO_MANY_ROWS then
dbms_output.put_line('查詢條件有誤,返回多條信息,請核實');
end;
記憶兩個
NO_DATA_FOUND:沒有找到數據
TOO_MANY_ROWS:結果集超過一行
分支結構
條件判斷
--sql中的條件判斷語句
if 條件 then
end if;
if 條件 then
else
end if;
if 條件 then
elsif 條件 then
。。。
else
end if;
案例:
declare
v_price1 number();
v_price2 number();
v_price3 number();
v_usenum2 number();
v_money number();
v_account t_account%rowtype;
--階梯水費計算
begin
if v_usenum2<=5 then
v_money:=v_price1*v_usenum2;
elsif v_usenum2>5 and v_usenum2<=10 then
v_money:=v_price1*5+ v_price2*(v_usenum2-5)
else
v_money:=v_price1*5+ v_price2*(v_usenum2-5)+v_price3*(v_usenum2-10)
循環
循環關鍵字:loop 循環語句 end loop;
--loop無條件循環
loop
循環語句
end loop;
--案例
declare
v_num number;
begin
v_num:=1;
loop
dbms_output.put_line(v_num);
v_num:=v_num+1;
--這是一個死循環,加條件推出
if v_num>100 then
exit;
(或者:exit when v_num>100;)
end loop;
end;
--loop有條件循環
while 滿足循環的條件
loop
循環語句
end loop;
--案例
declare
v_num number;
begin
v_num:=1;
while v_num<=100
loop
dbms_output.put_line(v_num);
v_num:=v_num+1;
end loop;
end;
--for循環
for 局部變量 in 條件
loop
循環語句
end loop;
--案例
declare
v_num number;
begin
for v_num in 1..100
loop
dbms_output.put_line(v_num);
end loop;
end;
游標
? 游標是系統為用戶開設的一個數據緩沖區,存放SQL語句的執行結果。
游標的作用
? 速度快!2017年開發人員基本不用游標了,但是在今后的學習中還要涉及到。
申明游標語法
cursor 游標名稱 is SQL語句
使用游標語法
open 游標名稱
loop
fetch 游標名稱 into 變量
--返回一個布爾值
exit when 游標名稱%notfound
end loop;
close 游標名稱
案例
--打印業主類型為1的價格表
--查表語句
select * from t_pricetable where ownertypeid=1
--游標
declare
cursor cur_pricetable is select * from t_pricetable where ownertypeid=1;--聲明游標
v_pricetable t_pricetable%rowtype;
begin
open cur_pricetable;
loop
fetch cur_pricetable into v_pricetable;
exit when cur_pricetable%notfound;
dbms_output.put_line('價格:'||v_pricetable.price||'噸位:'||v_pricetable.minnum||'到'||v_pricetable.maxnum);
end loop;
close cur_pricetable;
附:步驟
- PLSQL結構
- 聲明游標
- 打開--關閉游標
- 循環取記錄
帶參數的游標
? 聲明的時候指定參數的類型和名稱,打開游標的時候需要傳入指定類型的參數即可。
案例:
declare
v_pricetable T_PRICETABLE%rowtype;-- 價格行對象
cursor cur_pricetable(v_ownertypeid number) is select *from T_PRICETABLE where ownertypeid=v_ownertypeid;-- 定義游
標
begin
open cur_pricetable(2);-- 打開游標
loop
fetch cur_pricetable into v_pricetable;-- 提取游標到變量
exit when cur_pricetable%notfound;-- 當游標到最后一行下面退出循環
dbms_output.put_line('價格:'||v_pricetable.price ||'噸位:'||v_pricetable.minnum||'-'||v_pricetable.maxnum );
end loop;
close cur_pricetable;-- 關閉游標
end ;
For循環游標[掌握使用]
declare
begin
for v_pricetable in cur_pricetable(3)
end
存儲函數/存儲過程
存儲函數
? Oracle中提供的使用PLSQL語言自定義的一些函數稱之為存儲函數
語法格式
CREATE [or replace] function 函數名稱
(參數名稱 參數類型,參數名稱 參數類型,...)
return 結果變量數據類型
is
變量聲明部分
begin
邏輯部分
return 結果變量
[Exception]
end;
案例
--通過ID查找小區
create or replace function fn_getaddress
(v_id number)
return varchar2;
is
v_name varchar2(30);
begin
--查詢地址表
select name into v_name from t_address where id=v_id;
return v_name;
end;
實際使用語句
select id,name,fn_getaddress(addressid) from t_owners
存儲過程
概念
? 存儲過程和存儲函數差不多,和存儲函數相比,它沒有返回值,可以通過傳出參數返回多個值;存儲過程不能在select語句中直接使用,它多數是被應用程序調用。
存儲過程與存儲函數都可以封裝一定的業務邏輯并返回結果,存在區別如下:
- 存儲函數中有返回值,且必須返回;而存儲過程沒有返回值,可以通過傳出參數返回多個值。
- 存儲函數可以在 select 語句中直接使用,而存儲過程不能。過程多數是被應用程序所調用。
- 存儲函數一般都是封裝一個查詢結果,而存儲過程一般都封裝一段事務代碼。
語法格式
create [or replace] procedure procedure名稱 (參數名 參數類型,...)
is[as]--都可以用
變量聲明
begin
具體邏輯
[Exception]
end;
參數只指定類型,不指定長度
過程參數的三種模式:
? IN 傳入參數(默認)
? OUT 傳出參數 ,主要用于返回程序運行結果
? IN OUT 傳入傳出參數
案例
--創建不帶傳出參數的存儲過程:添加業主信息
--增加業主信息
create or replace procedure pro_owners_add()
使用
--調用不帶參數的存儲過程
--一
call 存儲過程名(實際參數。。。);
--二
begin
存儲過程的名稱(實參)
end;
用JDBC調用
--帶傳出參數的存儲過程
create or replace procedure pro_owners_add()
觸發器
? 已經淘汰,現在都用消息隊列
? 對特定表(增刪改---生產者消費者思想---中介思想)
概念: 數據庫觸發器就是一段sql程序
觸發器可用于
- 數據確認
- 實施復雜的安全性檢查
- 做審計,跟蹤表上所做的數據操作等
- 數據的備份和同步
觸發器的分類
- 前置觸發器(BEFORE)
- 后置觸發器(AFTER)
面向切面的AOP思想
創建觸發器的語法
create [or replace] trigger 觸發器名
before|after
[delete][[or] insert][[or]update[of 列名,...]]
on 表名
[for each row][when(條件)]
declare
...
begin
PLSQL 塊
end;
--for each row的作用是標準此觸發器是行級觸發器,不寫的話是語句級觸發器