oracle pl/sql

  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;

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章