oracle学习日志06

■ PL/SQL(Procedural Language/SQL,过程语言/SQL)
它是结合Oracle过程语言和结构化查询语言的一种扩展语言
PL/SQL支持多种数据类型,可以使用条件语句和循环语句等控制结构
PL/SQL可用于创建存储过程、触发器和程序包,也可以用来处理业务规则、数据库事件或给SQL命令的执行添加程序逻辑

PL/SQL语言是程序化程序设计语言。
块(Block)是PL/SQL程序中最基本的结构,所有PL/SQL程序都是由块组成。
块中包含过程化语句和SQL的DML语句。这些块可以按顺序出现,也可以相互嵌套(一个块在另一个块的内部)
块的分类
匿名块
匿名块是出现在应用程序中的没有名字且不存储到数据库中的块
匿名块出现在SQL语句可以出现的地方,它们可以调用其他程序,却不能被其他程序调用
命名块
命名块是一种带有标签的匿名块,标签为块指定了一个名称
子程序
子程序是存储在数据库中的过程(procedure)、函数(function),生成之后可以被多次执行

PL/SQL的块由变量声明、程序代码和异常处理代码3部分组成:
DECLARE
标记声明部分
变量的声明,必须要在begin前面
声明一些变量、常量、用户定义的数据类型及游标
name varchar(30); --声明时不设置值
name varchar(30):=‘Jack’;--声明带有默认值
name preson.name%type; --直接引用一个表的数据类型
BEGIN
标记主程序体部分开始
主程序体,在这里可以加入各种合法语句
EXCEPTION
标记异常处理部分开始
异常处理程序,当程序中出现错误时执行这一部分
END

标记主程序体结束部分

declare
说明部分 (变量说明,例外说明 〕
begin
语句序列 (DML语句〕…
exception
例外处理语句
End;

■ PL/SQL字符集

PL/SQL语言有效字符包括以下三类
所有大写和小写英文字母
0~9的阿拉伯数字
操作符,包括(、)、+、-、*、/、<、>、!、=、@、%等
PL/SQL标识符
标识符的最大长度为30个字符,不区分大小写,但建议在标识符中适当使用大小写,以增加程序的可读性。

■ PL/SQL常量和变量

在PL/SQL程序运行时,需要定义一些变量来存放一些数据。
常量和变量在使用前必须声明,可以使用DECLARE对变量进行声明,语法如下:
DECLARE
<变量名> <变量类型>:=默认值;
….
在DECLARE块中可以同时声明多个常量和变量。声明普通常量或变量是需要说明以下信息:
常量或变量的名称
常量或变量的数据类型

■ 声明常量

声明常量的基本格式如下:
<常量名> constant <数据类型> := <值>;
:= 为赋值语句
关键字constant表示声明的是常量。常量一旦定义,在以后的使用中其值不再改变。
一些固定的大小为了防止有人改变,最好定义成常量。
例如
Pass_Score constant INTEGER := 60 ;

■ 声明变量

声明变量的基本格式如下:
<变量名> <数据类型>[(宽度) := <初始值>];
变量声明是没有关键字,但要指定数据类型,宽度和初始值可以定义也可以不定义。
例如
Address VARCHAR2(30) := ‘地址未知’;
PL/SQL对一个未初始化的变量,将被默认赋值为NULL
例如
Address VARCHAR2(30);

例如
SET SERVEROUTPUT ON;
DECLARE
Pass_Score constant INTEGER:=60;
Address VARCHAR2(30):='北京海淀区';
BEGIN
DBMS_OUTPUT.PUT_LINE(Pass_Score);
DBMS_OUTPUT.PUT_LINE(Address);
END;

使用SET SERVEROUTPUT ON命令设置环境变量SERVEROUTPUT为打开状态,从而使PL/SQL程序能够在SQL*Plus中输出结果
使用函数DBMS_OUTPUT.PUT_LINE()可以输出参数的值

oracle学习日志06_第1张图片


■ 数据类型

%TYPE数据类型
当定义PL/SQL变量存放值时,必须确保变量使用合适的数据类型和长度,否则可能会在运行过程中出现PL/SQL运行错误
为了避免这种不必要的错误,可以使用%TYPE属性来定义变量
当使用%TYPE属性定义变量时,Oracle会自动地按照数据库表列或其他变量来确定新变量的类型和长度
%ROWTYPE数据类型
如果一张表中包含较多的列,则可以使用%ROWTYPE来定义一个表示表中一行记录的变量

declare
v_ename emp.ename%type;
v_deptno dept.deptno%type;
v_dept_row dept%rowtype;
begin
  select ename ,deptno into v_ename,v_deptno
			 from emp where empno=&eno;
  select * into v_dept_row from dept where deptno=v_deptno;
  dbms_output.put_line('您要查找的员工是:'||v_ename
			||',所在部门信息为:');
  dbms_output.put_line('部门编号:'||v_deptno||
	'  部门名称:'||v_dept_row.dname||'   所在地:'||v_dept_row.loc);
end; 
%record数据类型
类似高级语言中的结构
首先需要定义记录类型和记录变量
当引用记录成员时,必须将记录变量作为前缀

declare 
type emp_record_type is RECORD((--定义一个记录类型,包含员工信息
  ename emp.ename%type,
  sal emp.sal%type,
  comm emp.comm%type,
  total_sal sal%type);
v_emp_record emp_record_type;--声明记录类型变量
begin
  select ename,sal,nvl(comm,0),sal+nvl(comm,0) into v_emp_record
  from emp where empno=7369;
  dbms_output.put_line('员工姓名:'|| v_emp_record.ename);
  dbms_output.put_line('基本工资:'|| v_emp_record.sal);
  dbms_output.put_line('奖金:'|| v_emp_record.comm);
  dbms_output.put_line('实发工资:'|| v_emp_record.total_sal);
TABLE数据类型
TABLE(索引表)相当于一个键值集合,键是唯一的,用于查找对应的值。键可以是整数或字符串
示例:
将部门编号是10和20的部门信息存储到table类型中,然后输出其信息。
declare
type dept_table_type is table of dept%rowtype
index by binary_integer;
v_dept_table  dept_table_type;
begin
  select * into v_dept_table(0) from dept where deptno=10;
  select * into v_dept_table(1) from dept where deptno=20;
  dbms_output.PUT_LINE('编号:'||v_dept_table(0).deptno||'   名称:'
		||v_dept_table(0).dname||'   所在地:'||v_dept_table(0).loc);
  dbms_output.PUT_LINE('编号:'||v_dept_table(1).deptno||'   名称:'
		||v_dept_table(1).dname||'   所在地:'||v_dept_table(1).loc);
end;


■  PL/SQL程序的执行部分

接收用户的输入赋值

在declare之前,可以通过
accept someVar prompt ‘提示信息’;要求用户输入
在后面的代码中,可以通过地址引用&someVal接收这值
--接收用户的输入
set serveroutput on
--要求用户输入一个数字,如果不输入后面也可以直接引用,只是一个提示而已
accept age prompt 'plz enter a number:';
declare
nn number;
begin
nn := &age;
dbms_output.put_line('你输入的信息是'||nn);
end;

从查询中结果中赋值

用into关键字可以将查询结果的值,设置给变量:
set serveroutput on
declare 
   id number(4);
   nm varchar(30);
begin
   select  empno,ename into id,nm from emp where empno=7369;
   dbms_output.put_line('编号'||id||'名称'||nm);
   --以下是异常处理 -–可选
   exception
       when NO_DATA_FOUND then
          dbms_output.put_line('没有你要查询的数据');
       when others then
          dbms_output.put_line('其他错误');
end;

■ 流程控制语句

流程控制语句是所有过程性程序语言的关键
PL/SQL的主要控制语句如下:
if...then elsif … then end if;
判断if正确则执行then,否则执行else(elsif为嵌套判断)
注意elsif,里面少一下e.
Case var when … then when … then end
有逻辑的从数值中做出选择
Loop exit end loop
循环控制,用判断语句执行exit
Loop exit when … end loop
同上,当when为真时执行exit
while..loop end loop
for...in...loop end loop
已知循环次数的循环
IF语句

IF 条件表达式1 THEN
语句段1
ELSIF 条件表达式2 THEN
语句段2
ELSIF 条件表达式3 THEN
语句段3
......
ELSIF 条件表达式n
语句段n
END IF;

CASE语句

CASE
WHEN 条件表达式1 THEN
语句段1;
WHEN 条件表达式2 THEN
语句段2;
......
ELSE
语句段n;
END CASE;

循环语句LOOP..EXIT..END

此语句的功能是重复执行循环体中的程序块,直到执行EXIT语句,则退出循环。
LOOP...EXIT...END语句的语法结构如下
LOOP
<程序块 1>
IF <条件表达式> THEN
EXIT
END IF
<程序块 2>
END LOOP;


EXIT WHEN (结束语句)

此循环语句的功能是重复执行循环体中的程序块,直到满足EXIT WHEN后面的判断语句,则退出循环。
LOOP...EXIT WHEN...END语句的语法结构如下:
LOOP
<程序块 1>
EXIT WHEN <条件表达式>
<程序块 2>
END LOOP;

例:

重新实现1~4累加
 SET ServerOutPut ON;
 DECLARE
   varNum INTEGER := 1;
   varSum INTEGER := 0;
 BEGIN
   LOOP
     varSum := varSum + varNum;
     dbms_output.put_line(varNum);
     EXIT WHEN varNum = 4;
     dbms_output.put_line('+');
     varNum := varNum + 1;
   END LOOP;
   dbms_output.put_line('=');
   dbms_output.put_line(varSum);
 END

WHILE..LOOP..END LOOP(while循环)

此语句的功能是当WHILE后面的语句条件成立时,重复执行循环体中的程序块。
WHILE...LOOP...END LOOP语句语法结构如下:
WHILE <条件表达式> LOOP
<程序块>
END LOOP;

例:

再次实现1~4累加

DECLARE
  varNum INTEGER := 1;
  varSum INTEGER := 0;
BEGIN
  WHILE varNum <= 4  LOOP
    varSum := varSum + varNum;
    dbms_output.put_line(varNum);
    IF varNum < 4 THEN
      dbms_output.put_line('+');
    END IF;
    varNum := varNum + 1;
  END LOOP;
  dbms_output.put_line('=');
  dbms_output.put_line(varSum);
END


FOR..IN..LOOP..END LOOP(for循环)

此语句定义一个循环变量,并指定循环变量的初始值和终止值。每循环一次循环变量自动加1.
FOR...IN...LOOP...END LOOP语句的语法如下
FOR <循环变量> IN <初始值>..<终止值> LOOP
<程序块>
END LOOP;

例:

再次实现1~4累加
DECLARE
varNum INTEGER := 1;
varSum INTEGER := 0;
BEGIN
FOR varNum IN 1..4 LOOP
varSum := varSum + varNum;
dbms_output.put_line(varNum);
IF varNum < 4 THEN
dbms_output.put_line('+');
END IF;
END LOOP;
dbms_output.put_line('=');
dbms_output.put_line(varSum);
END;

FOR 循环变量 in [REVERSE] 初值表达式..终值表达式 LOOP
语句段;
END LOOP;

■ 异常处理

PL/SQL程序在运行过程中,可能会出现错误或异常现象
例如:无法建立到Oracle的连接或用0做除数。好的程序应该对可能发生的异常情况进行处理,异常处理代码在EXCEPTION块中实现
可以使用WHEN语句来定义异常。WHEN语句的使用方法如下:
EXCEPTION
WHEN <异常情况名> THEN
<异常处理代码>
WHEN <异常情况名> THEN
<异常处理代码>
...
WHEN OTHERS THEN
<异常处理代码>


预定义异常
针对一些常见的错误,PL/SQL预定义了一些异常错误
当PL/SQL程序违反了Oracle的规定或超出了系统规定的限制时,就会隐含地引发一个预定义的错误

预定义异常种类(红色的重点)

异常

说明

ACCESS_INTO_NULL

在未初始化对象时出现

CASE_NOT_FOUNF

CASE语句中的选项与用户输入的数据不匹配时出现

COLLECTION_IS_NULL

在给尚未初始化的表或数组赋值时出现

CURSOR_ALREADY_OPEN

用户试图重新打开已经打开的游标时出现。在重新打开游标前必须先将其关闭

DUP_VAL_ON_INDEX

用户试图将重复的值存储在使用唯一索引的数据库列中时出现

INVALID_CURSOR

在执行非法游标运算(fetch一个尚未打开的游标)时出现

INVALID_NUMBER

将字符串转换为数字时出现

LOGIN_DENIED

输入的用户名或密码无效时出现

NO_DATA_FOUND

在表中不存在请求的行时出现

SOTRAGE_ERROR

在内存损坏或PL/SQL耗尽内存时出现

TOO_MANY_ROWS

在执行SELECT INTO语句后返回多行时出现

VALUE_ERROR

在产生大小限制错误时出现。如,变量中的列值超出变量的大小

ZERO_DIVIDE

以零做除数时出现


向一个NUMBER类型的变量赋值字符串时,导致异常的发生
SET ServerOutPut ON;
DECLARE
  varNum NUMBER;
BEGIN
  varNum := 'abc';
EXCEPTION
  WHEN VALUE_ERROR THEN
    dbms_output.put_line('VALUE_ERROR');
END;

使用SQLCODE , SQLERRM输出错误信息:
set serveroutput on;
declare 
  j integer:=0;
begin
  j:='Jack';
  --如果出错,直接去异常处执行,以下行不会输出
  dbms_output.put_line('Value is setted');
  exception
    when others then
      --在异常中默认使用sqlerrm输出信息
      dbms_output.put_line(SQLCODE||'Other errors    '||sqlerrm);
end;

一些小练习

/*while-loop 比loop好用多了*/
declare
  v_sum integer := 0;
  v_num integer := 0;
begin
  v_num := '&num';
  if v_num < 6 then
    while v_sum < 6 loop
      v_sum := v_sum + v_num;
      dbms_output.put(v_num);
      /*exit when v_sum = 6;*/
      dbms_output.put('+');
      v_num := v_num + 1;
    end loop;
    dbms_output.put('=');
    dbms_output.put_line(v_sum);
     
  elsif v_num >= 6 and v_num < 11 then
    while v_sum < 11 loop
      v_sum := v_sum + v_num;
      dbms_output.put(v_num);
      /*exit when v_sum = 11;*/
      dbms_output.put('+');
      v_num := v_num + 1;
    end loop;
    dbms_output.put('=');
    dbms_output.put_line(v_sum);
  
  else
    while v_num < 19 loop
      v_sum := v_sum + v_num;
      dbms_output.put(v_num);
      /*exit when v_sum = 19;*/
      dbms_output.put('+');
      v_num := v_num + 1;
    end loop;
    dbms_output.put('=');
    dbms_output.put_line(v_sum);
  end if;
end;

/*对type进行坐标管理形成的数组*/
declare
  type dept_table_type is table of dept%rowtype index by binary_integer;
  v_dept_table dept_table_type;
begin
  select * into v_dept_table(0) from dept where deptno = 10;
  select * into v_dept_table(1) from dept where deptno = 20;
  dbms_output.put_line('编号:' || v_dept_table(0).deptno || '  名称' || v_dept_table(0)
                       .dname);
  dbms_output.put_line('编号:' || v_dept_table(1).deptno || '  名称' || v_dept_table(1)
                       .dname);
end;




你可能感兴趣的:(oracle学习日志06)