PL/SQL 02 聲明變量 declare


語法:
identifier [CONSTANT] datatype [NOT NULL] [:= | DEFAULT expr]

identifier:用於指定變量或常量的名稱。
CONSTANT:用於指定常量。當定義常量時,必須指定它的初始值,並且其數值不能變。
datatype:用於指定變量或常量的數據類型。
NOT NULL:用於強制初始化變量(不能為NULL)。當指定 NOT NULL 選項時,必須要為變量提供數值。
:= 用於為變量和常量指定初始值。
DEFAULT:用於為常量和變量指定初始值。
expr:用於指定初始值的 PL/SQL 表達式,可以是文本值、其他變量、函數等。


例:
v_ename    VARCHAR2(10);
v_sal      NUMBER(6,2);
v_balance  BINARY_FLOAT;  --Oracle 10g 新數據類型
c_tax_rate CONSTANT NUMBER(3,2):=5.5;
v_hiredate DATE;
v_valid    BOOLEAN NOT NULL DEFAULT FALSE;

v_sal emp.sal%TYPE;       --%TYPE
v_tax_sal v_sal%type;     --可以用變量的%TYPE


--復合變量

1、記錄變量(類似高級語言的結構體)
DECLARE
  TYPE emp_record_type IS RECORD(
    name emp.ename%TYPE,
    salary emp.sal%TYPE,
    title emp.job%TYPE);
  emp_record emp_record_type;
BEGIN
  select ename,sal,job into emp_record
  from emp where empno=7788;
  dbms_output.put_line('雇員名:'||emp_record.name); --記錄變量.記錄成員
END;


2、表變量(類似高級語言的數組)
需要注意,PL/SQL 表變量與高級語言的數組有所區別,高級語言數組的下標不能為負,但 PL/SQL 表變量的下標可以為負;高級語言數字的元素個數有限制,而PL/SQL 表變量的元素個數沒有限制,並且其下標沒有上下限。

DECLARE
  TYPE ename_table_type IS TABLE OF emp.ename%TYPE
  INDEX BY BINARY_INTEGER;
  ename_table ename_table_type;
BEGIN
  select ename into ename_table(-1) from emp
  where empno=7788;
  dbms_output.put_line('雇員名:'||ename_table(-1));
END;


3、嵌套表(Nested Table)
嵌套表類似於高級語言的數組。需要注意,高級語言數組和嵌套表的下標都不能為負值;高級語言的元素個數是有限制的,而嵌套表的元素個數是沒有限制的。嵌套表和 PL/SQL 表變量非常類似,但嵌套表可以作為表列的數據類型,而 PL/SQL 表變量不能作為表列的數據類型。當在表列中使用嵌套表時,必須首先 CREATE TYPE 語句建立嵌套表類型。

CREATE OR REPLACE TYPE emp_type AS OBJECT(
  name varchar2(10),
  salary number(6,1),
  hiredate date);
/
CREATE OR REPLACE TYPE emp_array IS TABLE OF emp_type;
/

對象類型 emp_type 用於存儲雇員信息,而 emp_array 是基於 emp_type 的嵌套表類型,它可以用於存儲多個雇員的信息。當建立了嵌套表類型之后,就可以在表列或對象屬性中將其作為用戶自定義數據類型來引用。但需要注意,當使用嵌套表類型作為表列時,必須要為其指定專門的存儲表。

CREATE TABLE department(
  deptno number(2),
  dname varchar2(10),
  employee emp_arry
) NESTED TABLE employee STORE AS employee;         --employee為存儲表


4、VARRAY(變長數組)
類似於嵌套表,它可以作為表列和對象類型屬性的數據類型。但需要注意,嵌套表的元素個數沒有限制,而 VARRAY 的元素個數是有限制的。當使用 VARRAY 時,必須首先建立 VARRAY 類型。

CREATE TYPE article_type AS OBJECT(
  title VARCHAR2(20),
  pub DATE
);
/
CREATE TYPE article_arry IS VARCHAR2(20) OF article_type;
/

對象類型 article_type 用於存儲文章信息,而 article_arry 則用於存儲多篇文章的信息,並且最多可以存儲 20 篇文章。當建立了 VARRAY 類型之后,可以在表或對象屬性將其作為用戶自定義數據類型來引用。

如:
CREATE TABLE author(
  id number(6),
  name varchar2(10),
  article article_arry
);

注意,嵌套表列數據需要存儲在專門的存儲表中,而 VARRAY 數據則與其他列數據一起存放在表段中。


--參照變量
參照變量是用於存放數值指針的變量。通過使用參照變量,可以使得應用程序共享相同對象,從而降低占用空間。


1、REF CURSOR
當使用顯式游標時,需要在定義顯式游標時指定相應的 SELECT 語句,這種顯式游標稱為靜態游標。當使用游標變量時,在定義游標變量時不需要指定 SELECT 語句,而是在打開游標時指定 SELECT 語句,從而實現動態的游標操作。

DECLARE
  TYPE c1 IS REF CURSOR;
  emp_cursor c1;
  v_ename emp.ename%TYPE;
  v_sal emp.sal%TYPE;
BEGIN
  OPEN emp_cursor FOR
    select ename,sal from emp where deptno=10;
  LOOP
    FETCH emp_cursor INTO v_ename,v_sal;
    EXIT WHEN emp_cursor%NOTFOUND;
    dbms_output.put_line(v_ename);
  END LOOP;
  CLOSE emp_cursor;
END;
/

c1 為 REF CURSOR 類型,而 emp_cursor 為游標變量,並且在打開游標變量時指定了其所對應的 SELECT 語句。


2、REF obj_type
當編寫對象類型應用時,為了共享相同對象,可以使用 REF 引用對象類型,REF 實際是指向對象實例的指針。

下面通過示例說明如何使用 REF。首先建立對象類型 home 和對象表 homes,然后插入數據。

CREATE OR REPLACE TYPE home_type AS OBJECT(
  street varchar2(50),
  city varchar2(20),
  state varchar2(20),
  zipcode varchar2(6),
  owner varchar2(10)
);
/
CREATE TABLE homes OF home_type;
insert into homes values('呼倫北路12號','呼和浩特','內蒙','010010','馬明');
insert into homes values('呼倫北路13號','呼和浩特','內蒙','010010','秦斌');
commit;

對象表 homes 存放着家庭所在地以及戶主姓名。假定每個家庭有四口人,當進行人口統計時,為了使得同一家庭的每個家庭成員可以共享家庭地址,可以使用 REF 應用 home_type 對象類型,從而降低占用空間。示例如下:

create table person(
  id number(6) primary key,
  name varchar2(10),
  addr REF home_type
);
insert into person select 1, '馬文',ref(p)
from homes p where p.owner='馬明';
insert into person select 2, '馬武',ref(p)
from homes p where p.owner='馬明';
insert into person select 3, '馬全',ref(p)
from homes p where p.owner='馬明';
insert into person select 4, '馬才',ref(p)
from homes p where p.owner='馬明';
commit;

當為 person 表插入數據時, addr 列將會存放指向 homes 表相應數據的地址指針。


--非 PL/SQL 變量
當在 SQL*Plus 或應用程序(例如 Pro*C/C++)中與 PL/SQL 塊之間進行數據交互時,需要使用 SQL*Plus 變量或應用程序變量完成。當在 PL/SQL 塊中引用非 PL/SQL 變量時,必須要在非 PL/SQL 變量前加冒號(“:”)。


1、使用 SQL*Plus 變量
在 PL/SQL 塊中引用 SQL*Plus 變量時,必須首先使用 VARIABLE 命令定義變量;而如果要在 SQL*Plus 中輸出變量內容,則需要使用 PRINT 命令。

var name varchar2(10)
begin
  select ename into :name from emp
  where empno=7788;
end;
SQL> print name;

NAME
--------------------------------
SCOTT


2、使用 Procedure Builder 變量
當在 PL/SQL 塊中引用 Procedure Builder 變量時,必須首先使用 CREATE 命令定義變量,而如果在  Procedure Builder 中輸出變量內容,則可以使用包 TEXT_IO。

PL/SQL> CREATE CHAR name LENGTH 10
PL/SQL> BEGIN
     +> SELECT ename INTO :name FROM emp
     +> WHERE empno=7788;
     +> END;
PL/SQL> TEXT_IO.PUT_LINE(:name);
SCOTT


3、使用 Pro*C/C++變量
當在 PL/SQL 塊中引用 Pro*C/C++ 程序的宿主變量時,必須首先定義宿主變量,而如果要輸出變量內容,則可以使用 printf()。

char name[10];
EXEC SQL EXECUTE
  BEGIN
    SELECT ename INTO :name FROM emp
    WHERE empno=7788l
  END;
END-EXEC;
printf("雇員名:%s\n",name);


--三個 SQL*Plus 小例子
1、輸出文本
SQL> DECLARE
  2    txt VARCHAR2(20);
  3  BEGIN
  4    txt:='HuangHeShiZGDeMuQin';
  5    dbms_output.put_line(txt);
  6  END;
  7  /
HuangHeShiZGDeMuQin

PL/SQL procedure successfully completed.


2、替代變量
SQL> DECLARE
  2    a BINARY_INTEGER;
  3    b BINARY_INTEGER;
  4  BEGIN
  5    a:=&x;
  6    b:=&y;
  7    dbms_output.put_line(a/b);
  8  END;
  9  /
Enter value for x: 9
old   5:   a:=&x;
new   5:   a:=9;
Enter value for y: 3
old   6:   b:=&y;
new   6:   b:=3;
3


3、SQL*Plus 變量賦值,並輸出
SQL> var zg VARCHAR2(10)
SQL> BEGIN
  2    :zg:='zhongguo';
  3  END;
  4  /

PL/SQL procedure successfully completed.

SQL> print zg;

ZG
--------------------------------
zhongguo



--實驗舉例
declare
  stuname varchar2(10):='張三';                      --聲明中賦值
  stubir date;
begin
  stubir:=to_date('2012-1-1','yyyy-mm-dd');          --程序體中賦值
  dbms_output.put_line('stuname的值是:'||stuname);
  dbms_output.put_line('stubir的值是:'||stubir);
end;


declare
  name emp.ename%type;   --變量類型參考表中某列類型
begin
  name:='john';
  dbms_output.put_line('name is :'||name);
end;


declare
  no001 emp.empno%type;
  name001 emp.ename%type;
begin
  select empno,ename  --將SQL查詢結果存入變量(必須返回一行,不能多行)
  into no001,name001
  from emp
  where empno=7369;
  dbms_output.put_line('no001 is :'||no001);
  dbms_output.put_line('name001 is :'||name001);
end;


declare
  type emptype is record(         --記錄變量(包含多個變量)
       no emp.empno%type,
       name emp.ename%type,
       date emp.hiredate%type
       );
  e emptype;
begin
  select empno,ename,hiredate
  into e
  from emp
  where empno=7369;
  dbms_output.put_line('no is :'||e.no);
  dbms_output.put_line('name is :'||e.name);
  dbms_output.put_line('date is :'||e.date);
end;


declare
  e emp%rowtype;     --記錄變量另一種寫法
begin
  select *
  into e
  from emp
  where empno=7369;
  dbms_output.put_line('no is :'||e.empno);
  dbms_output.put_line('name is :'||e.ename);
  dbms_output.put_line('date is :'||e.hiredate);
end;


declare 
  type etype is table of emp.ename%type    --表變量(多個類型相同的變量,相當於數組)
  index by binary_integer;
  enames etype;
begin
  enames(0):='SMITH';
  enames(1):='ALLEN';
  enames(2):='WARD';
  dbms_output.put_line(enames(0));
  dbms_output.put_line(enames(1));
  dbms_output.put_line(enames(2));
end;


--表變量舉例1

declare 
type cc is table of sys_dmp01%rowtype;----表類型 
v_tab cc;
i number default 1;
begin
select * bulk collect into v_tab      -----------查詢結果放到表類型中bulk collect (*換成字段會報錯?)
from sys_dmp01;                       -----------四條記錄
for i in 1..v_tab.count loop
  insert into aa(ml_id,
                mlmc,
                mlyt,
                mllb,
                ztmc,
                ztdx,
                qjs,
                bjs,
                xt_id)
  values(v_tab(i).ml_id,
                v_tab(i).mlmc,
                v_tab(i).mlyt,
                v_tab(i).mllb,
                v_tab(i).ztmc,
                v_tab(i).ztdx,
                v_tab(i).qjs,
                v_tab(i).bjs,
                v_tab(i).xt_id);
end loop;
end;


--表變量舉例2

declare 
type t is table of abc_t.s%type;
bl t;
i number default 1;

begin
select s bulk collect  into bl
from abc_t;

for i in 1..bl.count 
loop
    dbms_output.put_line(bl(i)); 
end loop;
end;


--表變量舉例3

declare 
  type t is table of abc_t.s%type;
  bl t;
  i number default 1;
  sm number default 0;
begin
 select s bulk collect  into bl
 from abc_t;

 dbms_output.put_line(1);

   while i<=bl.count
     loop
       loop
         sm:=sm+bl(i);
         i:=i+1;
         exit when sm>=60;
       end loop;
       sm:=0;
       dbms_output.put_line(i-1);
     end loop;
end;


--表變量舉例4 (判斷字段中3個連續的數字)tt2是排序后的tt1表,不然判斷會混亂
declare
  type t is table of tt2%rowtype;
  v_tab t;
begin
  select * bulk collect into v_tab    --*換成字段會報錯
  from tt2 ; 
  for i in 1 .. v_tab.count-2 loop    --這里減2是因為最后2個數字不用判斷,不然循環會報錯
    if v_tab(i+2).id - v_tab(i).id = 2 and v_tab(i+2).name = v_tab(i).name then
      dbms_output.put_line(v_tab(i).name||'-'||v_tab(i).id); 
      dbms_output.put_line(v_tab(i+1).name||'-'||v_tab(i+1).id); 
      dbms_output.put_line(v_tab(i+2).name||'-'||v_tab(i+2).id);
      dbms_output.put_line('----------'); 
    end if;      
  end loop;
end;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM