第一类:PL/SQL变量
(在DECLARE阶段被声明和初始化)
(*每一行只声明一个变量)
(在执行阶段被赋予新值)
(可以在PL/SQL之间传递值)
(通过标准输出包可以看到结果)

变量初始化和关键字:
identifier [CONSTANT] datatype [NOT NULL] [:= | DEFAULT expr];
[CONSTANT]  必须初始化,并且其值不能改变
[NOT NULL]  必须初始化,不能被赋予NULL值
:=          赋值操作符
DEFAULT     赋值

1.标量类型
declare
  v_city varchar2(30) NOT NULL := 'Beijing';
  v_location varchar2(13) := 'Atlanta';
  v_deptno number(2) NOT NULL := 10;
  v_mgr number(6) DEFAULT 100;
  v_hiredate date;
  v_date date := to_date('20110117','yyyymmdd');
  v_rowid rowid;
  b_flag boolean;
begin
  null;
end;
/

PL/SQL变量和数据库变量长度区别:
CHAR 32767BYTE       O8DATABASE 2000BYTE  O7DATABASE 256BYTE
VARCHAR2 32767BYTE   O8DATABASE 4000BYTE  O7DATABASE 2000BYTE
LONG     32760BYTE   2G 
LONG RAW 32760BYTE   2G
列名的优先级别高于变量!
HR@prod> declare
  2     last_name varchar2(25) := 'PFAY';
  3  BEGIN
  4     DELETE E WHERE LAST_NAME=LAST_NAME;
  5  END;
  6  /

PL/SQL procedure successfully completed.

HR@prod> select * from e;

no rows selected

/

变量输出测试:
例题一:创建一个匿名PL/SQL块,将下列字符输出到屏幕:"today is : 在此处显示当前时间"
set serveroutput on

begin
  DBMS_OUTPUT.PUT_LINE('today is : '||sysdate);
end;
/


变量的作用范围
declare
    v_var1 number := 123;
begin
        dbms_output.put_line('OUT: v_var1 :'||v_var1);
        declare
                v_var2 number := 456;
        begin
                dbms_output.put_line('IN: v_var1 :'||v_var1);
                dbms_output.put_line('IN: v_var2 :'||v_var2);
        END;
        -- dbms_output.put_line('IN: v_var2 :'||v_var2);  内部块中的变量不能被外部块使用. 去掉注释则报错
end;
/

输出结果:
OUT: v_var1 :123
IN: v_var1 :123
IN: v_var2 :456

PL/SQL procedure successfully completed.


语句块的标签 标签加载一个语句块开始的位置上.
当外部块和内部块出现同名变量时 借助标签 来区分,但这样的程序可读性太差,尽量不要使变量名重复.

<<outer>>
declare
    v_var1 number := 123;
begin
        dbms_output.put_line('OUT: v_var1 :'||v_var1);
        <<inner>>
        declare
                v_var1 number := 456;
        begin
                dbms_output.put_line('IN: v_var1 :'||v_var1);
                dbms_output.put_line('IN: outer v_var1 :'||outer.v_var1);
        END inner;
end outer;
/

SQL> /
OUT: v_var1 :123
IN: v_var1 :456
IN: outer v_var1 :123

PL/SQL procedure successfully completed.

SQL>  

使用select查询结果对变量赋值
 PL/SQL中的select必需使用into将选出结果存入变量之内

dq
HR@prod> l
  1  declare
  2    v_name varchar2(25);
  3    v_sal number;
  4  begin
  5    select last_name,salary into v_name,v_sal from employees where employee_id=100;
  6    dbms_output.put_line(v_name||' : '||v_sal);
  7* end;
HR@prod> /
King : 24000

PL/SQL procedure successfully completed.


使用%type参照方式定义变量的类型
 有时在程序中我们声明的变量 很多时候是为了存放表中的列数据
 这样我们自己定义变量类型时往往都是和表中列的类型及长度是一致的
 %type就可以避免繁杂的输入 直接可以参照表的某列的类型直接作为变量的类型
 这样即使表中的列的类型被修改了 程序中的类型也随之改变
 程序健壮性提高

declare
  v_name employees.last_name%type;
  v_sal number;
begin
  select last_name,salary into v_name,v_sal from employees where employee_id=100;
  dbms_output.put_line(v_name||' : '||v_sal);
end;
/


2.复合类型
数组:  先定义数组的类型 再将类型赋予变量  变量就变成了数组 (后面的record和plsql_table同理)
declare
  type no_list is varray (10) of number;
  x no_list :=no_list(1990,2010,1995);
begin
  dbms_output.put_line('no_list 1 is:'||x(1));
  dbms_output.put_line('no_list 2 is:'||x(2));
  dbms_output.put_line('no_list 3 is:'||x(3));
end;
/

记录(record):
    使用方法:
 1.先定义类型 类型中描述了 这是一个RECORD
 2.但却没有说明内部具体列的内容,定义自定义类型就是为了定义record内部都包含什么列.
 3.再将定义好的类型关联一个变量

 引用record类型中的值 记录名.内部列名

declare
empid number := 100;
type emp_record_type is record
    (ename employees.last_name%type,
     deptid employees.department_id%type,
     sal employees.salary%type);
emp_record emp_record_type;
begin
    select last_name,department_id,salary into emp_record from employees where employee_id=empid;
    dbms_output.put_line('The name is : '|| emp_record.ename);
    dbms_output.put_line('The deptno is : '|| emp_record.deptid);
    dbms_output.put_line('The salary is : '||emp_record.sal);
end;
/
*************************************************************************************************

声明一个record变量用来保存dept表的10号部门所有列的数据!


使用%rowtype来代替record的类型定义
 和%type类似 %type是参照一列的类型 
 而%rowtype是将表的所有列做为了record中的成员
 列名既是成员名
 使用%rowtype就必须在select中选择所有表的列
declare
emp_record employees%rowtype;
begin
   select * into emp_record from employees where employee_id=100;
   dbms_output.put_line(emp_record.last_name ||' : '|| emp_record.salary);
end;
/
*****************************************************************************************************

PL/SQL表(INDEX BY表):
类似于数组,但下标除了定义成数字外还可以定义为字符,定义成数值型下标时必须使用binary_integer类型
binary_integer类型相比number类型区别:
 存储的数据以二进制方式存储 占用更少的空间
 可以存储 -2147483747 - 2147483747之间的任意整数
 主要使用在PL/SQL表的下标类型上.不能出现在常规列的类型上.反之PL/SQL表的下标也不能使用number来取代

使用方法:
 1.先定义类型 指出下标是数字还是字符
 2.再类型关联变量

 引用PL/SQL表中的元素:表名(下标)

declare
type emp_table_type is table of varchar2(50) index by binary_integer;
emp_record emp_table_type;
begin
    emp_record(0) := 'KING';
    select last_name into emp_record(1) from employees where employee_id=100;
    dbms_output.put_line(emp_record(0) || ' : ' || emp_record(1));
end;
/
*******************************************************************************

特殊关键字引用方法:
declare
type emp_char_type is table of number index by varchar2(10);
emp_sal emp_char_type;
begin
    select salary into emp_sal('King') from employees where employee_id=100;
    emp_sal('A') := 1000;
    emp_sal('B') := 2000;
    dbms_output.put_line('The number of emp_sal is :'||emp_sal.count);
    dbms_output.put_line('The first index of emp_sal :'||emp_sal.first);
    dbms_output.put_line('The last index of emp_sal : '||emp_sal.last);
    dbms_output.put_line('The index before B is : '||emp_sal.prior('B'));
    dbms_output.put_line('The index after A is : '||emp_sal.next('A'));
    dbms_output.put_line('The value of King is : '|| emp_sal('King'));
    dbms_output.put_line('The value of A is : '|| emp_sal('A'));
    dbms_output.put_line('The value of B is : '|| emp_sal('B'));
end;
/

HR@prod> /
The number of emp_sal is :3
The first index of emp_sal :A
The last index of emp_sal : King
The index before B is : A
The index after A is : B
The value of King is : 24000
The value of A is : 1000
The value of B is : 2000

PL/SQL procedure successfully completed.


PL/SQL表的缺陷是:
 of 类型 的定义比较死板
  定义的类型是字符 所有值就只能存储字符
         定义的类型是数字 所有值就只能存储数字
 解决办法是使用PL/SQL表+record 可以随心所欲的存不同类型值

PL/SQL table+record :
 PL/SQL中不能直接使用select 需要使用select into 将查询结果插入到标量 再dbms_output打印标量


 1.先定义record类型,声明类型中包含哪些列
 2.再定义PL/SQL类型,PL/SQL表类型关联之前定义的record类型
 3.这样就将record作为了PL/SQL表中的元素
 4.再将PL/SQL类型关联到变量

 引用方法: 
  赋值:PL/SQL表名(下标)
  取值:PL/SQL表名(下标).record中的列名
declare
  TYPE emp_record_type IS RECORD
    (ename VARCHAR2(25),
    job VARCHAR2(10),
    sal NUMBER(7,2));

  type emp_table_type is table of emp_record_type
  index by binary_integer;
  emp_table emp_table_type;
begin
  select ename,job,sal into emp_table(0) from emp where empno=7369;
  dbms_output.put_line('index 0 : '||emp_table(0).ename);
end;
/


第二类:非PL/SQL变量(来源于环境或宿主语言如C,java)
 SQLPLUS里可以使用绑定变量来接收PL/SQL块的返回值
VARIABLE return_code NUMBER

variable g_message VARCHAR2(30)
begin
  :g_message := 'My First PL/SQL Block!'; 
end;
/

--在SQLPUS中用print命令可以显示绑定变量的值
print g_message