1. 程式人生 > >oracle儲存過程----變數的介紹及使用(PL/SQL)

oracle儲存過程----變數的介紹及使用(PL/SQL)

oracle儲存過程—-變數的介紹及使用

  學習一門語言,既然學會了hello word 的輸出,那就要關注下基礎,首先要熟悉儲存過程 中的變數型別。
  關於儲存過程變數有哪些 ,這樣的問題,我在百度上搜索,卻發現很多沒用的,最近在同事那裡,忽然看到一本《oracle從入門到精通》,搜了一下,發現了儲存過程 的東西,卻是PL/SQL 中的基礎知識 ,好尷尬啊。
這裡寫圖片描述
  通過學習,瞭解到了變數的一些知識。
變數的分類如下:

儲存過程中的變數:
一、標量型別 (有%TYPE)
二、複合型別
     (1)記錄型別 (有%ROWTYPE)
     (2)索引表型別(關聯陣列)
     (3
)varry變長陣列

一、標量型別

  標量型別,一種是常用的有NUMBERCHARVARCHAR2VARCHARNCHARNVARCHAR2LONGDATETIMESTAMP ,基本上oracle 資料庫認識的型別都可以直接用了。
  還有一些我覺得不常用的,PLS_INTEGERBINARY_INTEGERSIMPLE_INTEGER布林型別(可以用來儲存邏輯的值,不能用作定義表中的資料型別)
  另外還有一個最常用的 %TYPE
  因為上一篇已經簡單用過第一種,所以這裡介紹一下%TYPE
  %TYPE 這種方式定義的變數型別的方式和其他的有所不同,它利用已經存在的資料型別來定義新資料的資料型別。例如,當定義多個變數或常量時,只要前面使用過的資料型別,後邊的變數就可以利用%TYPE

引用,最常見的就是把表中的欄位型別作為變數或常量的資料型別。使用此種方式的好處有以下幾點:

  1. 利用%TYPE 方式定義的變數型別和被引用的常量資料型別保持一致,如果以前是VARCHAR 型別,現在要改成NUMBER 型別,那就只需要直接改資料表中的型別即可,對已寫好的儲存過程 沒有影響。
  2. 還有個好處就是,儲存過程 基本都會有表操作,這就避免了在資料傳入的時候,引發資料溢位或不符的情況。比如資料庫裡是VARCHAR(1) 這樣的,但是實際傳入的可能是張三 這樣的字串,肯定會導致在執行到這行資料的時候引發異常。如果能用%TYPE,那在呼叫儲存過程 的時候,就能丟擲錯誤。

如下圖所示:
  sex LY_DS.LY_NB%TYPE

,表示:
  定義一個變數sex,它的型別與表LY_DS中的欄位LY_NB` 型別一致。

create or replace procedure test_select_procedure
(sex  LY_DS.LY_NB%TYPE,countNum out number)
AS
BEGIN
select count(*) into countNum from ly_ds where LY_NB=sex;
dbms_output.put_line(countNum);
END;

二、複合型別

1、記錄型別

  如果在儲存過程中查詢結果中,是多列的情況,我們可能需要查詢到結果後,對其做引用名稱.成員名稱 這樣取值。上一篇中說到過,可以使用into,即如下寫法:

create or replace procedure test_select2_procedure
(sex  varchar)
AS
countNum number(10); --別忘了寫上具體的長度,並且以分號結束
maxId number(10); --別忘了寫上具體的長度,並且以分號結束
BEGIN
select count(*),max(id) into countNum,maxId from ly_ds where LY_NB=sex;
dbms_output.put_line(countNum);
dbms_output.put_line(maxId);
END;

  上邊的是一種寫法,就是into 後邊跟上定義好的多個標量型別 。但是如果欄位很多呢?
  顯而易見,再用這個into 就不合適了,記錄型別 就是解決這個的。

(1)定義type 的宣告寫法

  定義type 的寫法為 type type_name is record(col_name col_type); 這樣,括號裡可以寫多個,中間用 , 分割,但最後一個不能有 , ,具體如下:

set serveroutput on;
DECLARE
TYPE new_type IS RECORD   --以TYPE type_name IS RECORD開始
(
   v_ly_nl LY_DS.LY_NL%TYPE,
   v_ly_mc varchar(100) --最後不要加,   
);  --最後以 ;結束
v_obj new_type; --將新物件定義為剛才宣告的型別
BEGIN
 --into賦值給v_obj,會按照定義的type順序賦值
select ly_nl,ly_mc into v_obj from ly_ds where id='2'; 
dbms_output.put_line('第一個變數:'||v_obj.v_ly_nl);
dbms_output.put_line('第二個變數:'||v_obj.v_ly_mc);
END;

  輸出結果如下:

匿名塊已完成
第一個變數:22
第二個變數:王五
(2)通過%ROWTYPE 的宣告寫法

  %ROWTYPE 該型別是提取行記錄時常用的儲存資料的方式。這種宣告方式,可以直接引用表中的行作為變數型別,它同%TYPE 在優點上類似,避免因表中欄位的資料型別改變,而導致PL/SQL 塊出錯的問題。
  下邊是%ROWTYPE 的用法例子,挺簡單的:

set serveroutput on;
DECLARE
v_obj ly_ds%rowtype; --ROWTYPE不區分大小寫
BEGIN
 --into賦值給v_obj,會按照定義的type順序賦值
select * into v_obj from ly_ds where id='2'; 
dbms_output.put_line('第一個變數:'||v_obj.ly_nl);
dbms_output.put_line('第二個變數:'||v_obj.ly_mc);
END;

  注意一個地方,就是上邊的into 前邊,只能為 * ,如果要寫為具體的列,那就要寫全

2、索引表型別(關聯陣列)

  該型別與陣列相似,利用鍵值查詢對應的資料,但是這裡的鍵值同我們真正的陣列下標不同,這種索引表的下標,還可以為字串,真正的陣列下標都是數字。索引表中的資料可以是上邊介紹過的標量型別,也可以是記錄型別。當在賦值的過程中,對已存在的索引表下標重複賦值,則會替換以前的資料,這個很好理解。

  以下是我學習的時候,記錄的這部分內容,都寫在了下邊:

set serveroutput on;
DECLARE
  /**
   *宣告一個儲存ly_ds整行資料的索引表,下標為數字,
   *即 binary_integer
   */
  type index_row_type is table of ly_ds%rowtype
  index by binary_integer;

  /**
   *宣告一個儲存字串資料的索引表,下標也為數字,
   *即 pls_integer
   */
  type index_val_type is table of varchar2(10)
  index by pls_integer;

  /**
   *宣告一個儲存字串資料的索引表,下標為字串,
   *即 varchar(100)、varchar(10),必須給固定大小
   */
  type index_str_val_type is table of varchar2(100)
  index by varchar(10);
   /**
    *定義一個下標為數字,存ly_ds一行的變數
    */
  v_row index_row_type; 
  /**
   *定義一個下標為數字,存字串的變數
   */
  v_val index_val_type; 
  /**
   *定義一個下標為字串,存字串的變數
   */
  v_str_val index_str_val_type; 
BEGIN
 /**
  *為下標為數字的 字串索引表下標1賦值
  */
  v_val(1) :='正數'; 
  /**
  *為下標為數字的 字串索引表下標-1賦值
  */
  v_val(-1) :='負數'; 
  dbms_output.put_line('v_val中下標1的值:'||v_val(1));
  dbms_output.put_line('v_val中下標-1的值:'||v_val(-1));

  /**
  *將改行資料賦值給行變數的下標1上
  */
  select * into v_row(1) from ly_ds where id='2'; 
  dbms_output.put_line('v_row(1)中ly_mc的值:'||v_row(1).ly_mc);
  dbms_output.put_line('v_row(1)中ly_nl的值:'||v_row(1).ly_nl);

   /**
    *為下標為字串的 字串索引表的下標one賦值
    */
  v_str_val('one') :='java天下第一';  
   /**
    *為下標為字串的 字串索引表的下標test賦值
    */
  v_str_val('test') :='java天下無敵'; 
   /**
    *為下標為字串的 字串索引表的下標test1賦值
    */
  v_str_val('test1') :='java太可怕了'; 
  dbms_output.put_line('v_str_val中下標one的值:'||v_str_val('one'));
  dbms_output.put_line('v_str_val中下標test的值:'||v_str_val('test'));
  dbms_output.put_line('v_str_val中第一個值的下標:'||v_str_val.first);
  dbms_output.put_line('v_str_val中第一個下標對應的值:'||v_str_val(v_str_val.first));
  dbms_output.put_line('v_str_val中最後一個下標:'||v_str_val.last);
END;

  執行後會有下邊的結果:

匿名塊已完成
v_val中下標1的值:正數
v_val中下標-1的值:負數
v_row(1)ly_mc的值:王五
v_row(1)ly_nl的值:22
v_str_val中下標one的值:java天下第一
v_str_val中下標test的值:java天下無敵
v_str_val中第一個值的下標:one
v_str_val中第一個下標對應的值:java天下第一
v_str_val中最後一個下標:test1

  上邊有個特別注意的問題,就是,定義下標和儲存的值的時候,一定要給出大小,比如字串,不能寫成varchar ,必須要寫成varchar(100) 這樣有固定大小的型別。
  上邊我用了三種,一種是pls_integerbinary_integer ,一種是ly_ds%rowtype ,這兩種都有固定的大小,第一種是數字型別,它們有固定的大小,可以百度一下。如果定義了標量型別那種,必須要要給出大小,這個需要注意下。

3、varry變長陣列

  varry 陣列,是另一種儲存有序元素的集合。集合下標從1開始,比較適合較少的資料使用。具體如下:
  它有一個注意的地方,就是陣列在定義一個變數時候,一定要初始化 ,並且,在使用前 一定要先確定容量 。對於,在初始化時,已賦值的,可以不用定義儲存的大小了。這點與java 中的陣列是一樣的。

set serveroutput on;
DECLARE
  /**
   *宣告一個最多容納100個數的varry陣列,注意,它的下標是從1開始的。
   *即 binary_integer
   */
  type array_type is varray(100) of varchar(100);
  /**
   *分別定義一個直接賦值的和兩個未賦值的陣列。
   *注意:一定要初始化,但可以不賦值。對於沒有賦值的這種陣列,在用之前
   *也一定要先確定容量。
   */
  v_val_array array_type := array_type('one','two');
  v_val_array2 array_type := array_type();
  v_val_array3 array_type := array_type();
BEGIN
   /**
    *獲取第一個varry陣列中的值
    *varry的下標從1開始
    */
    dbms_output.put_line('v_val_array中下標1的值:'||v_val_array(1));
    dbms_output.put_line('v_val_array中下標2的值:'||v_val_array(2));


   /**
    *獲取第二個varry陣列中的值
    *因為第二個varry沒有初始化長度,所以通過extend方法,
    *為該陣列加一個空位
    */
    v_val_array2.extend;
    v_val_array2(1) :='aaa'; 
    v_val_array2.extend;
    v_val_array2(2) :='bbb'; 
    v_val_array2.extend;
    v_val_array2(3) :='ccc'; 
    dbms_output.put_line('v_val_array2中下標1的值:'||v_val_array2(1));
    dbms_output.put_line('v_val_array2中下標2的值:'||v_val_array2(2));
    dbms_output.put_line('v_val_array2中下標3的值:'||v_val_array2(3));

     /**
    *獲取第三個varry陣列中的值
    *因為第三個varry沒有初始化長度,所以通過extend方法
    *初始化空位
    */

  /**
    *獲取第二個varry陣列中的值
    *因為第二個varry沒有初始化長度,所以通過extend方法,
    *為該陣列初始化長度
    */
    v_val_array3.extend(v_val_array2.count());
    v_val_array3(1) :='ddd'; 
    v_val_array3(2) :='eee'; 
    v_val_array3(3) :='fff'; 
    dbms_output.put_line('v_val_array3中下標1的值:'||v_val_array3(1));
    dbms_output.put_line('v_val_array3中下標2的值:'||v_val_array3(2));
    dbms_output.put_line('v_val_array3中下標3的值:'||v_val_array3(3));
END;

  執行後的結果為:

匿名塊已完成
v_val_array中下標1的值:one
v_val_array中下標2的值:two
v_val_array2中下標1的值:aaa
v_val_array2中下標2的值:bbb
v_val_array2中下標3的值:ccc
v_val_array3中下標1的值:ddd
v_val_array3中下標2的值:eee
v_val_array3中下標3的值:fff

  上邊分別是三種情況,其中有extend ,可能新手會感到迷惑。
  因為v_val_array2v_val_array3 開始的時候,只是定義了變數,所以,在使用前,需要給出大小,extent 的用法,即是對陣列的長度加1個空位 的意思。
  如果想直接為v_val_array3給出固定大小,可以直接v_val_array3.extend(3) ,這樣就會給v_val_array3 一個預設的儲存大小為3 ,也可以通過已有陣列的大小,即是上邊的v_val_array3.extend(v_val_array2.count())

  雖然上邊都是PL/SQL 那邊的知識,但是它們在儲存過程 中,都是通用的。變數這地方,浪費了挺長的時間,但是基礎有利用後邊的學習,我覺得浪費了這兩天應該會對自己有用處的。
  下一篇 oracle儲存過程—-儲存過程執行簡單的增刪改查sql