pl/sql是什麼?
pl/sql(procedural language/sql)是oracle在標準的sql語言上的擴展,pl/sql不僅允許嵌入sql語言,還可以定義變量和常量,允許使用條件語句和循環語句,允許使用例外處理各種錯誤,這樣使得他的功能變得更加強大,使用pl/sql我們可以輕鬆的完成複雜的查詢要求
學習pl/sql的知識鋪墊:
<1.過程,函數,觸發器是pl/sql編寫
<2.過程,函數,觸發器是在oracle中的
<3.pl/sql是非常強大的數據語言
<4.過程,函數可以在java程序用調用
pl/sql的優點
<1.提高應用程序的運行性能
<2.模塊化的設計思想(分頁的過程,訂單的過程,轉賬的過程...)
<3.減少網絡傳入量
<4.提高安全性
pl/sql的缺點
移植性性不好
pl/sql的第一個小例子
創建表
SQL> create table mytest(
name varchar2(20),
pwd varchar2(30)
);
創建存儲過程
SQL> create procedure sp_test is
begin
insert into mytest values('lms','m123');
end;
/
調用該過程的方式的兩種方式
<1 exec 過程名(參數值1,參數值2......)
<2 call 過程名(參數值1,參數值2......) //注意這種方式在過程名後一定要帶括號
pl/sql的編程基礎單位是塊
簡單的分類如下
以塊爲基礎主要可以編寫四類東西:(存儲)過程,函數,觸發器,包
編寫規範
<1註釋
當行註釋 --
select * from emp where empno=7788;--取得員工信息
多行註釋 /*........*/
<2標識符號的命名規範
(1.當定義變量的時候,建議v_作爲前綴 v_sal
(2.當定義常量的時候,建議用c_作爲前綴 c_rate
(3.當定義遊標的時候,建議用_cursor作爲後綴 emp_cursor;
(4.當定義例外的時候,建議用e_作爲前綴e_error
塊
塊(block)是pl/sql的基本程序單元。編寫pl/sql程序實際上就是編寫pl/sql快。要完成相對簡單的應用工能,可能只需要編寫一個pl/sql塊;但是如果想要實現複雜的功能,可能需要在一個pl/sql塊中嵌套其它的pl/sql塊
塊的結構示意圖
pl/sql塊由三個部分構成:定義部分,執行部分,例外處理部分
如下所示:
declare
/*定義部分----定義常量,變量,遊標,例外,複雜數據類型*/
begin
/*執行部分----要執行的pl/sql語句和sql語句*/
exception
/*例外處理部分--處理運行的各種錯誤*/
end;
特別說明:
定義部分是從declare開始的,該部分是可選的
執行部分是從begin開始的,該部分是必須的
例外處理部分是從exception開始的,該部分是可選的
------輸出示例------
set serveroutput on;--打開輸出選項
begin
dbms_output.put_line('hello,word'); --調用包dbms_output下的存儲過程put_line(?),這個類似於java中的類
end;
-------變量示例------
declare
v_ename varchar(20);--定義變量
begin
select ename into v_ename from emp where empno=&empno;
dbms_output.put_line('用戶名是'||v_ename);
end;
declare
v_ename varchar(20);--定義變量
v_sal number(7,2);
begin
select ename,sal into v_ename,v_sal from emp where empno=&empno;
dbms_output.put_line('用戶名是'||v_ename||';薪水是'||v_sal);
end;
--&控制檯參數輸入符號
--------異常處理--------
爲了避免pl/sql程序運行錯誤,提高pl/sql的健壯性,應該對可能的錯誤進行處理,這個很有必要
比如,<1.在上面的例子中,當輸入了不存在的僱員號時,應當做例外處理
< 2.有時出現異常,希望用另外的邏輯處理
相關說明:oracle預定義了一些異常,no_data_found表示找不到數據的例外
例如:
SQL> declare
v_ename varchar(20);--定義變量
begin
select ename into v_ename from emp where empno=&empno;
dbms_output.put_line('用戶名是'||v_ename);
---異常處理
exception
when no_data_found
then dbms_output.put_line('朋友,你的編號輸入有誤');
end;
/
結果:朋友,你的編號輸入有誤
過程
過程用於執行特定的操作,當建立過程時,既可以輸入參數(in),也可以指定輸出參數(out),通過在過程中使用輸出參數(out).通過在過程中使用輸入參數,可以將數據傳遞到執行部分;通過使用輸出參數,可以將執行部分的數據傳遞到應用環境,在sqlplus中可以使用create procedure命令來建立過程
----------------傳參的存儲過程-------------
編寫帶參數的存儲過程:
create procedure sp_updateemp(updatename varchar2,newsal number) is
begin
update emp set sal=newsal where ename=updatename;
end;
調用命名存儲過程命令:exec sp_updateemp('SCOTT','1111');
函數
函數用於返回特定的數據,當建立函數時,在函數頭部必須包含return字句,而在函數體內必須包含return返回的數據。我麼可以用create function來建立函數,例如:
create function sp_fun1(spname varchar2) return number is
yearsal number(7,2);
begin
--執行部分
select sal*12+nvl(comm,0)*12 into yearsal from emp where ename=spname;
return yearsal;
end;
---執行方式--
--SQL> var abc number;
--SQL> call sp_fun1('SCOTT') into:abc;
--SQL> print abc;
包
包用於在邏輯上組合過程和函數,它由包規範和包體兩部分組成。
<1可以使用create package命令來創建包:
包的規範只包含了過程和函數的說明,但是沒有過程和函數的實現代碼。包體用於實現包規範中的過程和函數
eg:
create package sp_package is
procedure sp_updateemp(updatename varchar2,newsal number); --存儲過程
function sp_fun1(spname varchar2) return number ; --函數
end;
<2建立包體可以使用create package body命令
create or replace package body sp_package is
procedure sp_updateemp(updatename varchar2,newsal number) is
begin
update emp set sal=newsal where ename=updatename;
end;
function sp_fun1(spname varchar2) return number is
yearsal number(7,2);
begin
select sal*12+nvl(comm,0)*12 into yearsal from emp where ename=spname;
return yearsal;
end;
end;
--包的調用
--調用包sp_package下的updateemp()存儲過程
--exec sp_package.sp_updateemp('SCOTT',1200);
觸發器
觸發器是指隱含的執行的存儲過程,當定義觸發器時,必須要指定觸發的事件和觸發的操作,常用的觸發事件包括insert,update,delete語句,而觸發器操作實際就是一個pl/sql塊。可以使用create trigger來建立觸發器
特別說明:
我們會在後面
----------標量--------
eg:根據員工編號輸出僱員名稱,工資,個人所得稅
declare
c_taxrate number(3,2):=0.03; --稅率,賦值用:=
v_ename emp.ename%type; --僱員姓名, 此種定義的方式是使v_ename的大小隨着emp表中ename的大小而變化
v_sal number(7,2); --工資
v_taxsal number(7,2); --個人所得稅
begin
select ename,sal into v_ename,v_sal from emp where empno=&no;
v_taxsal:=c_taxrate*v_sal;
dbms_output.put_line('員工姓名是:'||v_ename||' 個人工資是:'||v_sal||' 個人所得稅是:'||v_taxsal);
end; 結果是:員工姓名是:SCOTT 個人工資是:1200 個人所得稅是:36
複合變量(composite)
用於存放多個值的變量,主要包括幾種:
<1. pl/sql記錄
<2.pl/sql表
<3.嵌套表
<4.varray
--記錄類型--
類似於c語言中的結構體
eg:
--定義一個pl/sql記錄類型,類型包含三個數據v_name,v_sal,v_job
declare
type emp_record_type is record(
v_name emp.ename%type,
v_sal emp.sal%type,
v_job emp.job%type);
--定義了一個sp_record變量,該變量類型是emp_record_type
sp_record emp_record_type;
begin
select ename,sal,job into sp_record from emp where empno=&no; --將查詢到的值一次性賦值到 sp_record 中
dbms_output.put_line('僱員姓名是:'||sp_record.v_name);
end;
--複合類型
類似於高級語言中的鏈表
--pl/sql表實例
declare
--定義了一個pl/sql表類型sp_table_type,該類型用於存放emp.ename%type類型的數據
--index by binary_integer表示下標是整數
type sp_table_type is table of emp.ename%type index by binary_integer;
--定義了sp_table_type類型的變量sp_table
sp_table sp_table_type;
begin
select ename into sp_table(2) from emp where empno=7788;
dbms_output.put_line('僱員姓名是:'||sp_table(2));
end;
--注意取得的可以隨意插入到table中的任何地方
參照變量
參照變量是指用於存放數值指針的變量,通過使用參照變量,可以使得應用程序共享相同對象,從而降低佔用的空間,在編寫pl/sql程序時,可以使用遊標變量(ref cursor)和對象類型變量(ref obj_type)兩種參照變量類型
declare
--定義遊標類型sp_emp_cursor
type sp_emp_cursor is ref cursor;
--定義一個遊標變量test_cursor
test_cursor sp_emp_cursor;
--定義變量
v_ename emp.ename%type;
v_sal emp.sal%type;
begin
--把teset_cursor和一個select結合
open test_cursor for select ename ,sal from emp where deptno=&no;
--循環取出
loop
fetch test_cursor into v_ename,v_sal;
exit when test_cursor%notfound;
dbms_output.put_line('僱員姓名是:'||v_ename||'薪資是:'||v_sal);
end loop;
close test_cursor;
end;
-----if語句;if--then-----
create or replace procedure sp_pro6(spName varchar2) is
v_sal emp.sal%type;
begin
select sal into v_sal from emp where ename=spName;
if v_sal<2000
then update emp set sal=sal*1.1 where ename=spName;
end if; --不能掉了這裏
end;
-------二重if語句-if--then--else---
create or replace procedure sp_pro6(spName varchar2) is
v_comm emp.comm%type;
begin
select comm into v_comm from emp where ename=spName;
if(v_comm<>0)then
update emp set comm=comm+100 where ename=spName;
else
update emp set comm=comm+200 where ename=spName;
end if;
end;
----------多重條件分支-if--then--elsif---else---
create or replace procedure sp_pro7(spEmpno number) is
v_job emp.job%type;
begin
select job into v_job from emp where empno=spEmpno;
if v_job='PRESIDENT'then
update emp set sal=sal+1000 where empno=spEmpno;
elsif v_job='MANAGER'then
update emp set sal=sal+500 where empno=spEmpno;
else
update emp set sal=sal+200 where empno=spEmpno;
end if;
end;
-----------循環語句loop 至少執行一回--相當與while-----
create table Users(
uno number(3),
uname varchar2(10)
);
create or replace procedure sp_user(spUname varchar2) is
v_num Users.Uno%type:=1;
begin
loop
insert into Users values(v_num,spUname);
v_num:=v_num+1;
exit when v_num=11; --退出時的判斷語句
end loop;
end;
-------------while循環--先判斷再循環---相當於do-while-------------
create or replace procedure sp_user(spUname varchar2) is
v_num Users.Uno%type:=11;
begin
while v_num<=20 loop
--執行
insert into Users values(v_num,spUname);
v_num:=v_num+1;
end loop;
end;
---------------for 循環-------------
create or replace procedure sp_user(spUname varchar2) is
begin
for i in 21..30 loop --如果想從30到20反過來插入則在in後面加關鍵字 reverse
--執行
insert into Users values(i,spUname);
end loop;
end;
---------------goto語句-------一般不常用-----------
---------------null語句---null語句不會執行任何操作,並且會直接將控制傳遞到下一條語句-,使用null語句主要是爲了提高代碼的可讀性-----------------
create or replace procedure sp_pro6(spName varchar2) is
v_sal emp.sal%type;
begin
select sal into v_sal from emp where ename=spName;
if v_sal<2000
then update emp set sal=sal*1.1 where ename=spName;
else
null;
end if; --不能掉了這裏
end;