Oracle-4 - :超級適合初學者的入門級筆記:plsql,基本語法,記錄類型,循環,遊標,異常處理,存儲過程,存儲函數,觸發器
初學者可以從查詢到現在的pl/sql的內容都可以在我這裏的筆記中找到,希望能幫到大家,視頻資源在 資源,
我自己的全套筆記在 筆記
在pl/sql中可以繼續使用的sql關鍵字有:update delete insert select--into commit rollback savepoint ,在這裏需要註意的是查詢跟以前有些不一樣了
plsql由三個塊組成:聲明部分,執行部分,異常處理部分
declare:在此聲明pl/sql用到的變量,類型及遊標,以及局部的存儲過程的和函數
begin:執行部分:過程及sql語句,即程序的主要部分
exception:執行異常部分,錯誤處理
end
其中執行部分是必要的
pl/sql之helloworld
set SERVEROUTPUT ON --首先必須執行此語句,否則沒有輸出
begin
dbms_output.put_line(‘hello world‘);
end; --下圖前三個均是沒有執行set serveroutput on 語句的執行結果,在執行完此語句才能有輸出
其中只有begin部分,和結束end,因為此語句不需要變量聲明就省去了declare部分,和exception錯誤部分
變量常量等的命名規則,下列標紅的就是建議使用的命名的開頭
實例:用pl/sql查詢出tno為t001的老師的名字並輸出
下面的select 語句是把查詢結果放到了變量v_name中然後輸出
declare
v_name TEACHER.TNAME%TYPE; --這裏是動態的獲取teacher表中tname字段的類型
v_tno varchar2(10);
begin
--普通查詢語句 :select * from teacher where tno =‘t001‘;
select tno,tname into v_tno,v_name from teacher where tno =‘t001‘;
SYS.DBMS_OUTPUT.PUT_LINE(v_name||‘,‘||v_tno);
end;
記錄類型:是把邏輯相關的數據作為一個單元存儲起來,其作用是存放互不相同但邏輯相關的信息,類似java中一個類的概念一樣
註意不能將select語句中的列賦值給布爾變量
declare
--在為一個變量賦值的時候的格式 : v_tno number(10) :=10; 自這裏 “:=”是賦值,判斷為=
--type 自定義名1 is record
type teacher_mas is record (
v_name TEACHER.TNAME%TYPE, --逗號
v_tno varchar2(10) --無標點符號
);
-- 定義一個記錄類型的成員變量
--自定義2 自定義名1 在這就相當於創建了一個對象
v_teacher_mas teacher_mas;
--如果字段特別多的話 我們可以使用:v_teacher_mas teacher%rowtype; 表示與teacher表中的所有的類型都一直 ,下面就直接可以查詢 * into v_teacher_mas 了
begin
--普通查詢語句 :select * from teacher where tno =‘t001‘;
select tno,tname into v_teacher_mas from teacher where tno =‘t001‘;
SYS.DBMS_OUTPUT.PUT_LINE(v_teacher_mas.v_name||‘,‘||v_teacher_mas.v_tno);
end;
流程控制語句:
if 語句結構: if 《條件表達式》 then ---- end if; 相當於 java中 if() {}
if 《條件表達式》 then -- else-- end if; 相當於java中的 if(){} else {}
if 《條件表達式》 then -- els if《條件表達式》-- endif;這裏是elsif 不是elseif 相當於java中的多重判斷了就 :if(){} elseif (){} eles{}
實例:--查詢sno為s001的學生的c001課程的成績,如果大於60輸出及格 小於60輸出不及格 其他輸出一般
每次的if或者elsif必須跟一個分隔符 用end if作為結束標誌,當然同一個if後可以加and
declare
v_score SC.SCORE%type;
begin
select score into v_score from sc where sc.sno=‘s001‘ and CNO=‘c001‘;
if v_score<60 then SYS.DBMS_OUTPUT.PUT_LINE(‘不及格‘);
elsif v_score >=60 then SYS.DBMS_OUTPUT.PUT_LINE(‘及格‘);
else SYS.DBMS_OUTPUT.PUT_LINE(‘一般‘);
end if;
end;
case語句結構:case 值
when 表達式 then
when 表達式 then
else
end;
由於case比較惡心,sno為s001的學生的c001課程的成績為78.9,看下查詢sql,在這裏case跟Java、中的switch一樣
case 一個值,when 後 只能跟常量,並且 then後不能賦值,輸出等,只可以返回結果
declare
v_score SC.SCORE%type;
v_mas varchar2(30);
begin
select score into v_score from sc where sc.sno=‘s001‘ and CNO=‘c001‘;
v_mas :=
case v_score when 78.9 then ‘及格‘
when 60 then ‘不及格‘
else ‘一般‘
end;
SYS.DBMS_OUTPUT.PUT_LINE(v_mas);
end;
循環結構: 實例 輸出1--100 用循環結構
1. loop...exit...where ....end loop
declare
v_min number(3):=1;
begin
loop
SYS.DBMS_OUTPUT.PUT_LINE(v_min);
exit when v_min >= 100;
v_min := v_min +1;
end loop;
end;
2. while<布爾表達式> loop 要執行的語句 end loop;
declare
v_i number(3):=1;
begin
while v_i <=100 loop
SYS.DBMS_OUTPUT.PUT_LINE(v_i);
v_i := v_i +1;
end loop;
end;
3. for 循環計數器 in【reverse】 上限 .. 下限 loop 要執行的語句 end loop;不要忘記上限於下限中間有兩個點
每循環一次變量自動+1,使用關鍵字reverse自動-1 ,跟在in reverse 後面的數字必須是從小到大的順序,而且必須是整數,不能是變量或者表達式,可以使用exit 退出循環
begin
for c in 1..100 loop
SYS.DBMS_OUTPUT.PUT_LINE(c);
end loop;
end;
標號與goto:無條件的跳到指定的標號去的意思
實例 :打印1到100 ,當打印到50的時候,打印結束循環,然後結束整個循環
declare
v_i number(3):=1;
begin
while v_i<=100 loop
if v_i=50
then goto label;
end if;
SYS.DBMS_OUTPUT.PUT_LINE(v_i);
v_i := v_i+1;
end loop;
<<label>>
SYS.DBMS_OUTPUT.PUT_LINE(‘結束循環‘);
end;
遊標的使用:類似java中的叠代器Iterator,遊標是一個指向上下文的句柄或指針,通過遊標,可以處理多行記錄
1. 顯示遊標處理
顯示遊標處理四步驟
1. 定義遊標:cursor --is -- 在指定數據類型時,不能使用長度約束
2. 打開遊標:open -- : 程序不能用open語句重復打開一個遊標
3. 提取遊標:fetch--into--
4. 關閉遊標: close--
遊標實例:打印出80號部門的所有員工的信息
declare
--記錄類型
type emp_mas is record(
v_empid employees.employee_id%type,
v_name employees.last_name%type,
v_sal employees.salary%type
);
--記錄類型對象
emp_mas_record emp_mas;
--定義遊標
cursor emp_ens_mas is select employee_id,last_name,salary from employees where department_id=80;
begin
--打開遊標
open emp_ens_mas;
--提取遊標
fetch emp_ens_mas into emp_mas_record;
--emp_ens_mas%found 相當於java中的hashNext
while emp_ens_mas%found loop
SYS.DBMS_OUTPUT.PUT_LINE(emp_mas_record.v_empid||‘,‘||emp_mas_record.v_name||‘,‘||emp_mas_record.v_sal);
fetch emp_ens_mas into emp_mas_record;
end loop;
--關閉遊標
close emp_ens_mas;
end;
2. 遊標的for循環:pl/sql提供了遊標for循環,自動執行遊標的open,fetch,close語句和循環語句的功能,當進入循環時,遊標for循環語句自動打開遊標,並提取
第一行遊標數據,當程序處理完當前所提取的數據而進入下一次循環時,遊標for循環語句會東子提取下一行數據供程序處理,當提取完結果
集中的所有數據行後結束循環,並自動遊標
格式:for 變量 in 遊標 loop -----end loop;
與上題一樣,打印出80號部門的所有員工的信息
declare
--定義遊標
cursor emp_ens_mas is select employee_id,last_name,salary from employees where department_id=80;
begin
for c in emp_ens_mas loop
SYS.DBMS_OUTPUT.PUT_LINE(c.employee_id||‘,‘||c.last_name||‘,‘||c.salary);
end loop;
end;
3. 異常的捕獲與處理
1. 預定義異常,就是已經系統定義好的一些異常,這些異常由系統自動拋出,如下
declare
v_i number(30);
begin
select salary into v_i from employees where employee_id >=100;
SYS.DBMS_OUTPUT.PUT_LINE(v_i);
end;
由於employee_id >= 100 的員工的工資返回的結果不止一個 ,所以這裏就會出現 返回值太多的一場
此時就可以在exception中捕獲此異常並進行處理,如果不處理的話,系統報錯並且程序整體終止
declare
v_i number(30);
begin
select salary into v_i from employees where employee_id >=100;
SYS.DBMS_OUTPUT.PUT_LINE(v_i);
exception
when Too_many_rows then SYS.DBMS_OUTPUT.PUT_LINE(‘返回值太多了!!‘);
when others then SYS.DBMS_OUTPUT.PUT_LINE(‘其他錯誤!!‘);
end;
上面捕獲的是系統預定義異常Too_many_rows ,如果產生其他不知道的異常可以使用others 進行捕獲並處理
2. 非預定義異常的處理
對於非預定異常的處理,首先必須對非定義的oracle錯誤進行定義,步驟
1. 在pl/sql塊的定義部分定義異常情況:<異常情況>exception;
2. 將其定義好的異常情況,與標準的oracle錯誤連接起來,使用 pragma exception_init 語句:pragma exception_init(<異常情況>,<異常代碼>);
3. 在pl/sql塊的異常情況處理部分對異常情況做出相應的處理
我們來刪除employee_id = 100的用戶
declare
begin
delete from employees where employee_id =100;
end;
這時候由於100號員工有子記錄,employee_id 等於 本表的manager_id,所以刪除不了
上面爆出來的錯誤代碼 2292 沒有在oracle中的預定義異常,我們這時候就只能自己定義錯誤名與此錯誤號相關聯
declare
my_exception exception;
pragma exception_init(my_exception,-2292);
begin
delete from employees where employee_id =100;
exception
when my_exception then SYS.DBMS_OUTPUT.PUT_LINE(‘違反約束 非預定義異常!!‘);
end;
3. 用戶自定義的異常處理
用戶自定義異常是通過顯示使用 raise 語句來觸發的,當引發一個異常錯誤的時候,控制就轉向到exception塊異常錯誤部分
對於這類異常情況的處理步驟如下
1. 在pl/sql塊的定義部分定義異常情況 <異常情況>exception;
2. raise <異常情況>
3. 在pl/sql塊的異常情況處理部分對異常情況做出相應的處理。
實例:查詢employee_id 為100 號員工的工資,如果工資>1w則拋出異常“工資高”
declare
my_exception exception;
v_i number(5) ;
begin
select salary into v_i from employees where employee_id =100;
if v_i>10000 then
raise my_exception; --出發自定義異常
end if;
exception
when my_exception then SYS.DBMS_OUTPUT.PUT_LINE(‘工資高!!‘);
end;
存儲函數與存儲過程
Oracle 提供可以把pl/sql程序存儲在數據庫中,並可以在任何地方來運行他,這樣就叫存儲過程或函數
過程和函數的唯一區別是函數總向調用者返回數據,而過程不返回
創建一個函數: 創建函數時如果重名直接覆蓋創建
1. 建立內嵌函數
語法: create or replace function 函數名 (id number ,name varchar2)
return number
is --需要使用的變量遊標等可以在這裏定義
begin --函數體
exception --異常接受處理
end;
實例,寫一個可以返回helloworld 的函數(無參函數)
create or replace function get_helloWorld
return varchar2
is
begin
return ‘Hello World‘;
end;
函數創建完成調用此函數:1. select GET_HELLOWORLD from dual;
2. begin
SYS.DBMS_OUTPUT.PUT_LINE(GET_HELLOWORLD);
end;
(有參函數):create or replace function get_helloWorld(name varchar2) --不需要指定長度
return varchar2
is
begin
return ‘Hello World ‘ || name;
end;
調用:select GET_HELLOWORLD(‘純菜鳥‘) from dual;
2. 關於out函數:pl/sql程序可以通過out型的參數實現有多個返回值
in參數標記表示傳遞給函數的值在該函數執行中不改變;out標記表示一個值在函數中進行計算並通過該參數傳遞給調用語句,in out 標記標識傳遞給函數的值可以變化
並傳遞給調用語句。若省去標記,則參數隱含為in 。return 包含返回結果的數據類型
實例:定義一個函數,獲取給定部門的工資總和 和 該部門的員工總數(定義為out類型的參數)
要求:部門號定義為參數,工資總額定義為返回值
創建函數: create or replace function get_salary(empid number,empNum out number)
return number
is
v_sal number(6) :=0;
cursor my_emp_cur is select salary from employees where department_id = empid;
begin
empNum :=0; --參數只能在函數體中賦值,如果不對請指正
for c in my_emp_cur loop
v_sal := c.salary + v_sal; --工資
empNum := empNum+1;
end loop;
return v_sal;
end;
調用函數:declare
v_count_people_number number(3);--存儲人數的變量
begin
SYS.DBMS_OUTPUT.PUT_LINE( get_salary(80,v_count_people_number));
SYS.DBMS_OUTPUT.PUT_LINE(v_count_people_number);
end;
--從調用函數這就可以看到,在上面out函數中並沒有顯示返回人數,但是在調用的時候,Oracle會帶回參數並存到自己定義的變量中,此時輸出只會輸出函數返回的結果,而輸出待會的參數
存儲過程創建:獲取給定部門的工資總和(out) ,要求:部門號和工資總額定義為參數
create or replace procedure get_sal(empid number,sum_sal out number)
is
cursor my_emp_cur is select salary from employees where department_id = empid;
begin
sum_sal :=0;
for c in my_emp_cur loop
sum_sal := sum_sal+c.salary;
end loop;
end;
我們發現存儲過程的語法格式與存儲函數的語法格式只是相差 過程是 procedure 無return,,而函數是function 有return
調用:declare
v_count_people_number number(7);
begin
get_sal(80,v_count_people_number);
sys.dbms_output.put_line(v_count_people_number);
end;
觸發器:類似過程和函數,都有聲明,執行,和異常處理過程的pl/sql塊,區別與存儲過程,存儲過程是由程序調用,而觸發器是由事件觸發調用,觸發器不能接受參數,Oracle事件指的是對表或視圖的增刪改
可以在增刪改操作前或者操作後進行觸發,可以對每個行或語句操作上進行觸發。
觸發器的組成:
1. 觸發事件:增刪改
2. 觸發時間:before after
3. 觸發器本身 :
4. 觸發頻率:語句級(statement)觸發器 和 行級(row)觸發器:例如更改一個表的工資,如果更改一個人的觸發一次就是行級,如果整個表更改前或後觸發就是語句級
創建觸發器的語法
create [or replace ] trigger 名字
before | after
insert | update | delete [of column]
on table
[for each row] --行級還是語句級的,寫上的話就是行級的,不寫就是語句級的
where ---
在teacher 表上的 tname 上添加觸發器:當更新update tname的時候 輸出:tname被更改
create or replace trigger tea_tname_up
after --事件之前被觸發
update of tname on teacher --作用在teacher 表上的tname列中,也可以直接作用在表上,去掉行就行 直接on table
--不寫就是語句級的,寫for each row 就是行級的
begin --被觸發後做的事情
SYS.DBMS_OUTPUT.PUT_LINE(‘tname被更改‘);
end;
當更新:update teacher set tname =‘純菜鳥‘ where tid=1; 時
:new 和 :old修飾符:比如更改表中的數據,用這兩個就可以看到更新前和更新後的數據
修改上面的觸發器,使其tname更改後,輸出更改前的和更改後的
create or replace trigger tea_tname_up
after
update of tname on teacher
for each row --作用與每行,使用new 和old 必須加上這個
begin
SYS.DBMS_OUTPUT.PUT_LINE(‘修改前的:‘||:old.tname||‘ 修改後的:‘||:new.tname);
end;
更改tname:update teacher set tname =‘懶蛋‘ where tid=1;
實例:當刪除teacher 表中的數據的時候,吧刪除的數據備份到 teacher_bak;
teacher中的數據
teacher_bak中的數據
觸發器創建:create or replace trigger teacher_two_bak
after
delete on teacher
for each row
begin
insert into teacher_bak values (:old.tid,:old.tname);
end;
測試:delete from teacher where tid = 1;
執行完後,teacher 與 teacher_bak 中的數據分別是
......
Oracle-4 - :超級適合初學者的入門級筆記:plsql,基本語法,記錄類型,循環,遊標,異常處理,存儲過程,存儲函數,觸發器