黑馬程式設計師--Oracle學習_day06
---------- android培訓 、java培訓、期待與您交流! ----------
學習目標:1,理解oracle的pl/sql的概念
2,掌握pl/sql程式設計技術(包括編寫過程、函式、觸發器...)
學習的必要性:
1,提高應用程式的執行效能
2,模組化的設計思想
3,減少網路傳輸量
4,提高安全性
名言:程式要用靈魂,一定要讓你的東西做得好一些。
pl/sql的缺點:
1,移植性不好
1,pl/sql的介紹
pl/sql(procedural language/sql)是oracle在標準的sql語言上的擴充套件。pl/sql不僅允許嵌入sql語言,還可以定義變數種常量,允許使用條件語句和迴圈語句,允許使用例外處理各種錯誤,這樣使得它的功能變得更加強大。
a,過程,函式,觸發器是pl/sql編寫
b,過程,函式,觸發器是在oracle中
c,pl/sql是非常強大的資料庫過程語言
d,過程,函式可以在java程式中呼叫
·sql plus開發工具
sql plus是oracle公司提供的一個工具,這個之前介紹過的。
舉一個簡單的案例:
編寫一個儲存過程,該過程可以向某表中新增記錄。
·pl/sql developer開發工具
pl/sql developer是用於開發pl/sql塊的整合開發環境(ide),它是一個獨立的
產品,而不是oracle的一個附帶品。
舉一個簡單的案例:
編寫一個儲存過程,通過該過程可以刪除某表記錄。
2,pl/sql
開發人員使用pl/sql編寫應用模組時,不僅需要掌握sql語句的編寫方法,還要要掌握pl/sql語句及語法規則。pl/sql程式設計可以使用變數和邏輯控制語句,從而可以編寫非常有用的功能模組。比如:分頁儲存過程模組、訂單處理儲存過程模組、轉賬儲存過程模組...而且如果使用pl/sql程式設計,我們可以輕鬆的完成非常複雜的查詢要求。
·簡單分類
----過程(儲存過程)
----函式
塊(程式設計)
----觸發器
-----包
·編寫規範
1)註釋
a) 單行註釋 --
select * from emp where empno=7788;--取得員工資訊
b)多行註釋 用
2)識別符號號的命名規範
a) 當定義變數時,建議用v_作為字首 v_sal
b) 當定義常量時,建議用c_作為字首 c_rate
c) 當定義遊標時,建議用_cursor作為字尾 emp_cursor
d) 當定義例外時,建議用 e_作為字首 e_error
·塊,是pl/sql的基本程式單元,編寫pl/sql程式實際上就是編寫pl/sql塊。
要完成相對簡單的應用功能,可以只需要編寫一個pl/sql;但是是如果要 想實現複雜的功能,可以需要在一個pl/sql塊中巢狀其它的pl/sql塊。
1)塊結構示意圖
pl/sql塊由三個部分構成:定義部分、執行部分、例外處理部分。
如下所示:
declear
/*定義部分-------定義常量、變數、遊標、例外、複雜資料型別*/
begin
/*執行部分-------要執行的pl/sql語句和sql語句*/
exception
/*例外處理部分------處理執行的各種錯誤*/
end;
2)例項1只包括執行部分的pl/sql塊
set serverout put on --開啟輸出選項
begin
dbms_outpput.put_line(‘hello’);
end;
相關說明:
dbms_output是oracle所提供的包,該包包含一些過程,put_line就是dbms_output的一個過程。
3)例項2包含定義部分和執行部分的pl/sql
declare
v_ename varchar2(5); --定義字串變數
begin
insert ename into v_eanme from emp where empno=&no;
dbms_output.put_line(‘僱員名:’ || v_ename);
end;
相關說明:
&表示要接收從控制檯輸入的變數。
4)例項3包含定義部分、執行部分和例外處理部分
為了避免pl/sql程式的執行錯誤,提高pl/sql的健壯性,應該對可能出現的錯誤進行處理,這個很有必要:
a,比如例項2中,如果輸入了不存在的僱員號,應當做例外處理。
b,有時出現異常,希望用另外的邏輯處理,我們看看如何完成a
的要求
相關說明:oracle事先預定義了一些例外,no_data_found就是找不到資料的例外。
·過程
過程用於執行特定的操作,當建立過程時,既可以指定輸入引數(in),也可以指定輸出引數(out)。通過在過程中使用輸入引數,可以將資料傳遞到執行部分;通過使用輸出引數,可以將執行部分的資料傳遞到應用環境,在sqlplus中可以使用create procedure 命令來建立過程。
例項如下:
a,請考慮編寫一個過程,可以輸入僱員名,新工資 可以修改僱
員的工資。
b,如何呼叫過程有兩種方法。exec and call
c,如何在java程式中呼叫一個儲存過程。
?如何使用過程返回值
·函式
函式用於的返回特定的資料,當建立函式時,在函式頭部必須包含return子句,而在函式體內必須包含return語句返回的資料。我們可以使用create function 來建立函式。
實際案例:輸入僱員的姓名,返回該僱員的年薪
create function xp_fun2(xpName varchar2) return
number is YearSal number(7,2);
begin --執行部分
select sal*12+nvl(comm,0)*12 into YearSal from emp where ename=xpName;
return YearSal;
end;
在sqlplus中呼叫函式
sql>var result number
sql>call xp_fun2(‘SCOTT’) into:result;
sql>print result;
同樣我們可以在java程式中呼叫該函式
select annual_income(‘SCOTT’) from dual;//這樣
可以通過
·包
包用於在邏輯上組合過程和函式,它由包規範和包體兩部分組成。
1)我們可以使用create package命令來建立包:
例項:
create package xp_package is
procedure update_sal(name varchar2,newsl number);
function annual_income(name varchar2) return number;
end
包的規範只包含了過程和函式的說明,但沒有過程和函式的實現程式碼。包體用於實現規範中的過程和函式。
2)建立包體可以使用create package body命令。
create package body xp_package is
procedure update_sal(name varchar2,newsal number) is
begin
update emp set sal=newsal where ename=name;
end;
function annual_income(name varchar2)
return number is annual_salary number;
begin
select sal*12+nvl(comm,0) into annual_salary
from emp where ename=name;
return annual_salary;
end;
end;
3) 如何呼叫包的過程或是函式
當呼叫包的過程或是函式時,在過程和函式前需要帶有包名,如果需要訪問其它方案的包,還還需要在包名前加方案名。
如:
sql>call sp_package.update_sal(‘SCOTT’,1500);
特別說明:
包是pl/sql中非常重要的部分,我們在使用過程分頁時,將會再次體驗它的威力呵呵。
·觸發器
觸發器是指隱含的執行的儲存過程。當定義觸發器時,必須要指定觸發的事件和觸發的操作,常用的觸發事件包括insert,update,delete語句,而觸發操作實際就是一個pl/sql塊。可以使用create trigger來建立觸發器。
特別說明:
我們會在後面詳細為大家介紹觸發器的使用,因為觸發器是非常有用的,可維護資料庫的安全和一致性。
·定義並使用變數
在編寫pl/sal程式時,可以定義變數和常量;在pl/sal程式中包括有:
1)標題型別(scalar)
標量:在編寫pl/sql塊時,如果要使用變數,需要定義部分定義變數。
pl/sql中定義變數和常量的語法如下:
indentifier constant datatype not null := default expr;
indentifier:名稱
constant:指定常量,需要指定它的初始值,且其值是不能改變的。
datatype:資料型別
not null:指定變數值不能為null
:= 給變數或是常量指定初始值
default 用於指定初始值
expr : 指定初始值的pl/sql表示式,可是文字值、其它變數、函式等。
·標量案例:
1定義一個變長字串
v_ename varchar2(10);
2,定義一個小數,範圍-9999.99 ~ 9999.99
v_sal number(6,2);
3,定義一個小數並給一個初始值為5.4 := 是pl/sql的賦值符號
v_sal2 number(6,2):=5.4;
4,定義一個日期型別的資料
v_hiredate date;
5,定義一個布林變數,不能為空,初始值為false
v_valid boolean not null default false;
案例:輸入員工號,顯示僱員姓名、工資、個人所得稅(0.03),說明變數的使用。
declare
c_tax_rate number(3,2):=0.03;
v_ename varchar2(5);
v_sal number(7,2);
v_tax_sal number(7,2);
begin
select ename,sal into v_ename,v_sal from emp where empno=&no;
v_tax_sal:=v_sal*c_tax_rate;--計算所得稅
dbms_output.put_line('姓名是:'||v_ename||'工資:'||v_sal||'交稅: '||v_tax_sal);
end;
·標量(scalar)使用%type型別
對於上面的pl/sql塊有一個問題:
就是如果員工的姓名超過了5個字元的話,就會有錯誤,為了降低pl/sql程式的維護工作量,可以使用%type屬性定義變數,這樣它會按照資料庫列來確定你定義的變數的型別和長度,
例如:識別符號名 表名.列名%type;
2)複合型別(composite),用於存放多個值的變數,主要包括這幾種:
a,pl/sql記錄
類似與高階語言中的結構體,需要注意的是,當引用pl/sql記錄成員時,
必須要加記錄變數作為字首(記錄變數.記錄成員)如下:
declare
type emp_record_type is record(
name emp.ename%type;
salary emp.sal%type;
title emp.job%type);
sp_record emp_record_type;
begin
select ename,sal,job into sp_record from emp where empno=7788;
dbms_output.put_line(‘員工名:’||sp_record.name);
end;
b,pl/sql表
相當於高階語言中的陣列,但是需要注意的是在高階語言中陣列的下標不能為負數,而pl/sql是可以為負數的,並且元素的下標沒限制。例項如下:
declare
type sp_table_type is table of emp.ename%type
index by binary_integer;
sp_table sp_table_type;
begin
select ename into sp_table(0) from emp where empno=7788;
dbms_output.put_line(‘員工:’||sp_table(0));
end;
說明:
sp_table_type 是pl/sql表型別
emp.ename%type 指定表的元素的型別和長度
sp_table 為pl/sql表變數
sp_table(0) 則表示下標為0的元素
c,巢狀表
d,varray
3)參照型別(reference)
引數變數是指用於存放數值指標的變數,通過使用參照變數,可以使得應用程式共享相同物件,從而降低佔用的空間。在編寫pl/sql程式時,可以使用遊標變數(ref cursor)和物件型別變數(ref obj_type)兩種參照變數型別。
a,參照變數 ref cursor遊標變數
使用遊標時,定義遊標時不需要指定相應的select語句,但是當使用遊標時(open時)需要指定select語句,這樣一個遊標就與一個select語句結合了。例項如下:
請使用pl/sql編寫一個塊,可以輸入部門號,並顯示該部門所有員工姓名和他的工資,在些基礎上,如果某個員工的工資低於200元,就增加100元。
declare
type sp_emp_cursor is ref cursor; --定義遊標型別
test_cursor sp_emp_cursor; --定義遊標變數
v_ename emp.ename%type; --定義兩個變數
v_sal emp.sal%type;
begin
--把test_cursor和一個select結合
open test_cursor for select ename,sal from emp where deptno=&no;
--迴圈取出
loop
fetch test_cursor into v_ename,v_sal;
--判斷工資高低,決定是否更新
if v_sal<200 then update emp set sal=v_sal+100
where ename=v_ename;
--判斷是否test_cursor為空
exit when test_cursor%notfound;
dbms_output.put_line('姓名:'||v_ename||'工資:'||v_sal);
end loop;
end;
4)lob(large object)