• pl/sql编程


    pl/sql编程

    pl/sql编程

    一、什么是pl/sql

    pl/sql(procedural language/sql)是Oracle在标准的sql语言上的扩展,pl/sql不仅允许嵌入Sql语言,还可以定义变量和常量,允许使用条件语句和循环语句,允许使用例外处理各种错误,这样使得它的功能变得更加强大。

    二、pl/sql学习的必要性

    1、提高应用程序的运行性能。

    2、模块化的设计思想。

    3、减少网络传输量。

    4、提高安全性。

    三、编写规范

    单行注释--

    sql>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快。

    1、块结构示意图

    pl/sql块由三个部分构成:定义部分、执行部分、例外处理部分。

    declear:定义部分是从declare开始的,这部分是可选的。定义常量、变量、游标例外、复杂数据类型。

    begin:执行部分是从begin开始的,这部分是必须的。

    exception:例外处理部分是exception开始的,该部分可选的。

    A、包含定义部分和执行部分的pl/sql块

    declare

    v_ename varchar2(5); --定义字符串变量

    begin

    select ename int o v_ename from emp where empno=&no;

    dbms_output.put_line('雇员名:' || v_ename);

    相关说明:

    & 表示要接收从控制台输入的变量

    B、包含定义部分、执行部分和例外处理部分

    为了避免pl/sql程序的运行错误,提高pl/sql的健壮性,应该对可能的错误今夕处理,这个很有必要。

    declare

    v_ename varchar2(5); --定义字符串变量

    begin

    select ename int o v_ename from emp where empno=&no;

    dbms_output.put_line('雇员名:' || v_ename);

    exception

    when no_data_found then

    dbms_output.put_line('输入有误');

    过程用于执行特定的操作,当建立过程时,即可以指定输入参数(in),也可以指定输出参数(out),通过在过程中使用输入参数,可以将数据传递到执行部分,通过使用输出参数,可以将执行部分的数据传递到应用环境。在sqlplus中可以使用create procedure命令来建立过程。

    请考虑编写一个过程,可以输入雇员们,新工资,可修改雇员的工资。

    create procedure Update_Sal(spName varchar2,new sal number) is

    begin

    update emp set sal = newSal where ename = spName;

    如何调用过程有两种方法:

    A、exec Update_Sa('Scott',4678);

    B、call Update_Sal'Scott',4567);

    函数用于返回特定的数据,当建立函数时,在函数头部必须包含return子句,而在函数体内必须包含return语句返回的数据,我们可以使用create function 来建立函数。

    create function annual_income(name varchar2)

    return numeber is annual_salary number(7,2);

    begin

    select sal*12+nvl(comm,0)*12 into annual_salary from emp where ename=name;

    return annual_salary;

    在sqlplus中调用函数

    sql>var income number

    sql>call annual_income('SCOTT') into: income;

    sql>print income;

    包用于在逻辑上组合过程和函数,它由包规范和包体两部分组成

    1、我们可以使用create package命令来创建包。

    create package sp_package as

    procedure update_sal(name varchar2,new sal number);

    function annual_income(name varchar2) return number;

    包的规范只包含了过程和函数的说明,但是没有过程和函数的实现代码。包体用于实现包规范中的过程和函数。

    2、建立包体可以使用create package body命令

    create package body sp_package as

    procedure Update_Sal(spName varchar2,new sal number) is

    begin

    update emp set sal = newSal where ename = spName;

    function annual_income(name varchar2)

    return numeber is annual_salary number(7,2);

    begin

    select sal*12+nvl(comm,0)*12 into annual_salary from emp where ename=name;

    return annual_salary;

    3、如何调用包的过程或是函数

    当调用包的过程或是函数时,在过程和函数前需要带有包名,如果要访问其他方案的包,还需要在包名前加方案名。

    sql>call sp_package.update_sal('SCOTT',1500);

    八、定义并使用变量

    概述:在编写pl/sql程序时,可以定义变量和常量。在pl/sql程序中包括有标量类型(scalar)、复合类型(composite)、参照类型(references)、lob(large object)。

    1、标量(scalar)

    在编写pl/sql块时,如果要使用变量,需要在定义部分定义变量。

    pl/sql中定义变量和常量的语法如下:

    identifier [constant] datatype [not null] [:=| default expr]

    identifier:名称

    constant:指定常量。需要指定它的初始值,其其值是不能改变的。

    datatype:数据类型

    not null:指定变量值不能为NULL

    :=:给变量或是常量指定初始值

    default:用于指定初始值

    expr:指定初始值pl/sql表达式,可是文本值、其他变量、函数等。

    标量定义的案例

    (1)定义一个变长字符串

    v_ename varchar2(10);

    (2)定义一个小数,范围-9999.99~9999.99

    v_sal number(6,2);

    (3)定义一个小数并给一个初始值为5.4 :=是pl/sql的赋值号

    v_sal2 number(6,2):=5.3;

    (4)定义一个日期类型的数据

    v_hiredate date;

    (5)定义一个布尔变量,不能为空,初始值为false

    v_valid boolean not null default false;

    A、使用标量

    在定义好变量后,就可以使用这些变量。这里需要 说明的是pl/sql块为变量赋值不同于其他的编程语言,需要在等号前面加冒号(:=)。

    下面以输入员工号,显示雇员姓名、工资、个人所得税(税率为0.03)为例,说明变量的使用,看看如何编写。

    declare

    c_tax_rate number(3,2):=0.03;

    v_ename varchar2(5);

    v_sal number(7,2);

    v_tax number(7,2);

    begin

    select ename,sal into v_ename,v_sal from emp where empno=&no;

    v_tax:=v_sal*c_tax_rate;

    dbms_output.put_line('姓名是:'||v_ename||' 工资是:'||v_sal||' 所得税是:'||v_tax);

    B、使用%type类型

    对于上面的pl/sql块有一个问题:

    就是如果员工的姓名超过了5字符的话,就会有错误,为了降低pl/sql程序的维护工作量,可以使用%type属性定义变量,这样它会按照数据库列来确定你定义的变量的类型和长度。

    语法:标识符名 表名.列名%type;

    declear

    c_tax_rate number(3,2):=0.03;

    v_ename emp.ename%type;

    v_sal emp.sal%type;

    v_tax number(7,2);

    begin

    select ename,sal into v_ename,v_sal from emp where empno=&no;

    v_tax:=v_sal*c_tax_rate;

    dbms_output.put_line('姓名是:'||v_ename||' 工资是:'||v_sal||' 所得税是:'||v_tax);

    2、复合变量(composite)

    用于存储多个值的变量。主要包括这几种pl/sql记录、pl/sql表、嵌套表、varray。

    1、pl/sql记录

    类似于高级语言中的结构体,需要注意的是,当引用pl/sql记录成员时,必须要加记录变量作为前缀(记录变量.记录成员)。

    declare

    type emp_record_type is record(name emp.ename%type, salary emp.sal%type,title emp.job%type);

    sp_record emp_record_type;

    begin

    select ename,sal,job into sp_record from emp where empno=7788;

    dbms_output.put_line('员工名:'||sp_record.name);

    2、pl/sql表

    相当于高级语言中的数组,但是需要注意的是在高级语言中数组的下标不能为负数,而pl/sql是可以为负数的,并且表元素的下标没有限制。

    declare

    type sp_table_type is table of emp.ename%type index by binary_integer;

    sp_table sp_table_type;

    begin

    select ename into sp_table(0) from emp where empno=7788;

    dbms_output.put_line('员工名:'||sp_table(0));

    sp_table_type:是pl/sql表类型

    emp.ename%type:指定了表的元素的类型和长度

    sp_table:是pl/sql表变量

    sp_table(0):表示下标为0的元素

    3、参照变量

    概述:参照变量是指用于存放数值指针的变量,通过使用参照变量,可以使得应用程序共享相同对象,从而降低占用空间。在编写pl/sql程序时,可以使用游标变量(ref cursor)和对象类型变量(ref obj_type)两种参照变量类型。

    1、游标变量(ref cursor)

    使用游标时,当定义游标时不需要指定相应的select语句,但是当使用游标时(open时)需要指定select语句,这样一个游标就与一个select 语句结合了。

    请使用pl/sql编写一个块,可以输入部门号,并显示该部门所有员工姓名和他的工资

    declare

    type sp_emp_cursor is ref cursor;

    test_cursor sp_emp_cursor;

    v_ename emp.ename%type;

    v_sal emp.sal%type

    begin

    opent test_cursor for select ename,sal from emp where deptno=&no;

    fetch test_cursor into v_ename,v_sal;

    exit when test_cursor%notfound

    dbms_output.putline('姓名:'||v_ename||' 工资:'||v_sal);

    endloop;

    close test_cursor;

    九、控制结构

    概述:在任何计算机语言(C、Java、Pascal)都有各种控制语句(条件语句、循环结构、顺序控制结构),在pl/sql中也存在这样的控制结构。

    1、条件分支语句

    pl/sql中提供了三种条件分支语句。if-then、if-then-else、if-then-elsif-else。

    (1)简单的条件判断if-then

    案例:编写一个过程,可以输入一个雇员名,如果该雇员的工资低于2000,就给该雇员工资增加10%。

    create procedure IncreaseSal(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 sal=sal+sal*10% where ename=spName;

    end if;

    (2)二重条件分支if-then-else

    案例:编写一个过程,可以输入一个雇员名,如果该雇员的补助不是0,就在原来的基础上增加100;如果补助为0就把补助设为200。

    create procedure IncreaseComm(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;

    update emp set comm=200 where ename=spName;

    end if;

    (3)多重条件分支if-then-elsif-else

    案例:编写一个过程,可以输入一个雇员编号,如果该雇员的职位是PRESIDENT就给他的工资增加1000,如果该雇员的职位是MANAGER就给他的工资增加500,其他职位的雇员工资增加200。

    create procedure IncreaseSal(spNo number) is

    v_job emp.job%type;

    begin

    select job into v_job from emp where empno=spNo;

    if v_job='PRESIDENT' then

    update emp set sal=sal+1000 where empno=spNo;

    elsif v_job='MANAGER'

    update emp set sal=sal+500 where empno=spNo;

    update emp set sal=sal+200 where empno=spNo;

    end if;

    2、循环语句

    (1)基本循环

    loop是pl/sql中最简单的循环语句,这种循环语句以loop开头,以end loop结尾,这种循环至少会被执行一次。

    案例:编写一个过程,可输入用户名,并循环添加10个用户到Users表中,用户编号从1开始增加。

    create procedure AddUser(spName varchar2) is

    v_num number(2):=1;

    begin

    insert into Users values(v_num,spName);

    exit when v_num=10;

    v_num:=v_num+1;

    endloop;

    (2)While循环

    基本循环至少要执行循环体一次,而对于while循环来说,只有条件为true时,才会执行循环体语句,while循环以while 条件 loop开始,以end loop结束。

    编写一个过程,可输入用户名,并循环添加10个用户到Users表中,用户编号从11开始增加

    create procedure AddUser(spName varchar2) is

    v_num number(3):=11;

    begin

    while v_num<=20 loop

    insert into Users values(v_num,spName);

    v_num:=v_num+1;

    endloop;

    (3)for循环

    基本for循环的基本结构如下

    begin

    for i in reverse 1..10 loop

    insert into Users values(i,'Kevin');

    end loop;

    3、顺序控制语句

    (1)goto语句

    goto语句用于跳转到特定标号去执行有车,注意由于使用goto语句会增加程序的复杂度,并使得应用程序可读性变差,所以在一般应用开发时,建议大家不要使用goto语句

    基本语法如下:

    goto label:其中label是已经定义好的标号名。

    declare

    i number(4):=1;

    begin

    dbms_output.put_line("输出i='||i");

    if i=10 then

    goto end_loop

    end if;

    i:=i+1;

    endloop;

    <<end_loop>>

    dbms_output.put_line("循环结束");

    (2)null

    null语句不会执行任何操作,并且会直接将控制传递到下一条语句。使用null语句的主要好处是可以提高pl/sql的可读性。

    declare

    v_sal emp.sal%type;

    begin

    select sal into v_sal from emp where ename=spName;

    if v_sal<2000 then

    update emp sal=sal+sal*10% where ename=spName;

    null;

    end if;

    十、编写分页过程

    概述:分页时任何一个网站(bbs、网上商城、Blog)都会使用到的技术,因此学习pl/sql编程开发就一定要掌握该技术。

    案例:编写一个过程完成分页。

    --创建一个包,存放游标。

    create package ListPackage as

    type page_cursor is ref cursor;

    --开始编写分页的过程

    create procedure PagedList(

    tableName in varchar2, --要查询的表名

    sortColumn in varchar2, --欲排序的列名

    pagesize in number, --每页显示的记录数

    currentPage in number, --当前页号

    myRowCount out number, --表中总共的记录数

    myPageCount out number, --共有多少页

    p_cursor out ListPackage.page_cursor --游标变量

    v_sql varchar2(1000);

    v_begin number:=(currentPage-1)*pagesize+1;

    v_end number:=currentPage*pagesize;

    begin

    v_sql:='select * from(select *, rownum rn from (select * from '||tableName||' order by '||sortColumn||') t1 where rownum<='||v_end||') where rn>='||v_begin;

    open p_cursor for v_sql;

    --计算myRowCount和myPageCount

    v_sql:='select count(*) from '||tableName;

    execute immediate v_sql into myRowCount;

    if mod(myRowCount,pagesize)=0 then

    myPageCount:=myRowCount/pagesize;

    myPageCount:=myRowCount/pagesize+1;

    end if;

    close p_cursor;

    十一、例外处理

    1、例外的分类

    Oracle将例外分为预定义例外、非预定义例外和自定义例外三种。

    预定义例外:用于处理常见的Oracle错误。

    非预定义例外:用于处理预定义例外不能处理的例外。

    自定义例外:用于处理与Oracle错误无关的其他情况。

    2、处理预定义例外

    预定义例外时由pl/sql所提供的系统例外。当pl/sql应用程序违反了Oracle规定的限制时,则会隐含的触发一个内部例外。pl/sql为开发人员提供了二十多个预定义例外。我们给大家介绍常用的例外。

    (1)预定义例外case_not_found

    在开发pl/sql块中编写case语句时,如果在when子句中没有包含必须的条件分支,就会触发case_not_found的例外。

    create procedure sp_pro6(spno number) is

    v_sal emp.sal%type;

    begin

    select sal into v_sal from emp where empno=spno;

    when v_sal<1000 then

    update emp set sal=sal+100 where empno=spno;

    when v_sal<2000 then

    update emp set sal=sal+200 where empno=spno;

    end case;

    exception

    when case_not_found then

    dbms_output.put_line('case语句没有与'||v_sal||'相匹配的条件');

    (2)预定义例外cursor_already_open

    当从新打开已经打开的游标时,会隐含的触发例外cursor_already_open。

    declare

    cursor emp_cursor is select ename,sal from emp;

    begin

    open emp_cursor;

    for emp_record1 in emp_cursor loop

    dbms_output.put_line(emp_record1.ename);

    end loop;

    exception

    when cursor_already_open then

    dbms_output.put_line('游标已经打开');

    (3)预定义例外dup_val_on_index

    在唯一索引所对应的列上插入重复的值时,会隐含的触发例外dup_val_on_index例外。

    begin

    insert into dept values(10.'公关部','北京');

    exception

    when dup_val_on_index then

    dbms_output.put_line('在deptno列上不能出现重复值');

    (4)预定义例外invalid_cursor

    当试图在不合法的游标上执行操作时,会触发该例外。

    例如:视图从没有打开的游标提取数据,或是关闭没有打开的游标。则会触发该例外。

    declare

    cursor emp_cursor is select ename,sal from emp;

    emp_record emp_cursor%rowtype;

    begin

    fetch emp_cursor into emp_record;

    dbms_output.put_line(emp_record.ename);

    close emp_cursor;

    exception

    when invalid_cursor then

    dbms_output.put_line('请检查游标是否打开');

    (5)预定义例外invalid_number

    当输入的数据有误时,会触发该例外。

    案例:数字100写成了1oo就会触发该例外

    begin

    update emp set sal=sal+'1oo';

    exception

    when invalid_number then

    dbms_output.put_line('输入数字不正确');

    (6)预定义例外no_data_found

    下面是一个pl/sql块,当执行select into没有返回行,就会触发该例外。

    declare

    v_sal emp.sal%type;

    begin

    select sal into v_sal from emp where ename='&name';

    exception

    when no_data_found then

    dbms_output.put_line('不存在该员工');

    (7)预定义例外too_many_rows

    当执行select into语句时,如果返回超过了一行,则会触发该例外。

    declare

    v_ename emp.ename%type;

    begin

    select ename into v_ename from emp;

    exception

    when too_many_rows then

    dbms_output.put_line('返回了多行');

    (8)预定义例外zero_divide

    当执行除0操作时,则会触发给例外。

    (9)预定义例外value_error

    当在执行赋值操作时,如果变量的长度不足以容纳实际数据,则会触发该例外value_error。

    declare

    v_ename varchar2(5);

    begin

    select ename into v_ename from emp where empno=&no;

    dbms_output.put_line(v_ename);

    exception

    when value_error then

    dbms_output.put_line('变量尺寸不足');

    (10)其它预定义例外

    A、login_denide

    当用户非法登录时,会触发该例外。

    B、not_logged_on

    如果用户没有登录就执行dml操作,就会触发该例外。

    C、storage_error

    如果超出了内存空间或是内存被损坏,就触发该例外。

    D、timeout_on_resourece

    如果Oracle在等待资源时,出现超时就触发该例外。

    3、非预定义例外

    非预定义例外用于处理与预定义例外无关的Oracle错误,使用预定义例外只能处理21个Oracle错误,而当使用pl/sql开发应用程序时,可能会遇到其他的一些Oracle错误。比如在pl/sql快中执行dml语句时,违反了约束规定等等。在这样的情况下,也可以处理Oracle的各种例外。

    4、处理自定义例外

    预定义例外和非预定义例外都是Oracle错误相关的,并且处在的Oracle错误会隐含的触发相应的例外。而自定义例外与Oracle错误没有任何关联,它是由开发人员为特定情况所定义的例外。

    案例:请编写一个pl/sql块,接收一个雇员的编号,并给该雇员工资增加1000元,如果该雇员不存在请提示。

    create procedure IncreaseSal(spno number) is

    myException exception;

    begin

    update emp set sal=sal+100 where empno=spno;

    if sql%not_found then

    raise myException;

    end if;

    exception

    when myException then

    dbms_output.put_line('没有更新任何用户');

    十二、Oracle视图

    概述:视图是一个虚拟表,其内容由查询定义,同真实表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在,行和列数据来自有定义视图的查询所引用的表,并且在引用视图时动态生成。

    1、视图与表的区别

    A、表需要占用磁盘空间,视图不需要。

    B、视图不能添加索引。

    C、使用视图可以简化复杂查询。

    D、视图有利于提高安全性。

    2、创建视图

    create view 视图名 as select语句[with read only]

    3、创建或修改视图

    create or replace view 视图名 as select语句[with read only]

    4、删除视图

    drop view 视图名

    文章优化有问题?点击这里反馈URL给我们么是pl/sql

    pl/sql(procedural language/sql)是Oracle在标准的sql语言上的扩展,pl/sql不仅允许嵌入Sql语言,还可以定义变量和常量,允许使用条件语句和循环语句,允许使用例外处理各种错误,这样使得它的功能变得更加强大。

    二、pl/sql学习的必要性

    1、提高应用程序的运行性能。

    2、模块化的设计思想。

    3、减少网络传输量。

    4、提高安全性。

    三、编写规范

    单行注释--

    sql>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快。

    1、块结构示意图

    pl/sql块由三个部分构成:定义部分、执行部分、例外处理部分。

    declear:定义部分是从declare开始的,这部分是可选的。定义常量、变量、游标例外、复杂数据类型。

    begin:执行部分是从begin开始的,这部分是必须的。

    exception:例外处理部分是exception开始的,该部分可选的。

    A、包含定义部分和执行部分的pl/sql块

    declare

    v_ename varchar2(5); --定义字符串变量

    begin

    select ename int o v_ename from emp where empno=&no;

    dbms_output.put_line('雇员名:' || v_ename);

    相关说明:

    & 表示要接收从控制台输入的变量

    B、包含定义部分、执行部分和例外处理部分

    为了避免pl/sql程序的运行错误,提高pl/sql的健壮性,应该对可能的错误今夕处理,这个很有必要。

    declare

    v_ename varchar2(5); --定义字符串变量

    begin

    select ename int o v_ename from emp where empno=&no;

    dbms_output.put_line('雇员名:' || v_ename);

    exception

    when no_data_found then

    dbms_output.put_line('输入有误');

    过程用于执行特定的操作,当建立过程时,即可以指定输入参数(in),也可以指定输出参数(out),通过在过程中使用输入参数,可以将数据传递到执行部分,通过使用输出参数,可以将执行部分的数据传递到应用环境。在sqlplus中可以使用create procedure命令来建立过程。

    请考虑编写一个过程,可以输入雇员们,新工资,可修改雇员的工资。

    create procedure Update_Sal(spName varchar2,new sal number) is

    begin

    update emp set sal = newSal where ename = spName;

    如何调用过程有两种方法:

    A、exec Update_Sa('Scott',4678);

    B、call Update_Sal'Scott',4567);

    函数用于返回特定的数据,当建立函数时,在函数头部必须包含return子句,而在函数体内必须包含return语句返回的数据,我们可以使用create function 来建立函数。

    create function annual_income(name varchar2)

    return numeber is annual_salary number(7,2);

    begin

    select sal*12+nvl(comm,0)*12 into annual_salary from emp where ename=name;

    return annual_salary;

    在sqlplus中调用函数

    sql>var income number

    sql>call annual_income('SCOTT') into: income;

    sql>print income;

    包用于在逻辑上组合过程和函数,它由包规范和包体两部分组成

    1、我们可以使用create package命令来创建包。

    create package sp_package as

    procedure update_sal(name varchar2,new sal number);

    function annual_income(name varchar2) return number;

    包的规范只包含了过程和函数的说明,但是没有过程和函数的实现代码。包体用于实现包规范中的过程和函数。

    2、建立包体可以使用create package body命令

    create package body sp_package as

    procedure Update_Sal(spName varchar2,new sal number) is

    begin

    update emp set sal = newSal where ename = spName;

    function annual_income(name varchar2)

    return numeber is annual_salary number(7,2);

    begin

    select sal*12+nvl(comm,0)*12 into annual_salary from emp where ename=name;

    return annual_salary;

    3、如何调用包的过程或是函数

    当调用包的过程或是函数时,在过程和函数前需要带有包名,如果要访问其他方案的包,还需要在包名前加方案名。

    sql>call sp_package.update_sal('SCOTT',1500);

    八、定义并使用变量

    概述:在编写pl/sql程序时,可以定义变量和常量。在pl/sql程序中包括有标量类型(scalar)、复合类型(composite)、参照类型(references)、lob(large object)。

    1、标量(scalar)

    在编写pl/sql块时,如果要使用变量,需要在定义部分定义变量。

    pl/sql中定义变量和常量的语法如下:

    identifier [constant] datatype [not null] [:=| default expr]

    identifier:名称

    constant:指定常量。需要指定它的初始值,其其值是不能改变的。

    datatype:数据类型

    not null:指定变量值不能为NULL

    :=:给变量或是常量指定初始值

    default:用于指定初始值

    expr:指定初始值pl/sql表达式,可是文本值、其他变量、函数等。

    标量定义的案例

    (1)定义一个变长字符串

    v_ename varchar2(10);

    (2)定义一个小数,范围-9999.99~9999.99

    v_sal number(6,2);

    (3)定义一个小数并给一个初始值为5.4 :=是pl/sql的赋值号

    v_sal2 number(6,2):=5.3;

    (4)定义一个日期类型的数据

    v_hiredate date;

    (5)定义一个布尔变量,不能为空,初始值为false

    v_valid boolean not null default false;

    A、使用标量

    在定义好变量后,就可以使用这些变量。这里需要 说明的是pl/sql块为变量赋值不同于其他的编程语言,需要在等号前面加冒号(:=)。

    下面以输入员工号,显示雇员姓名、工资、个人所得税(税率为0.03)为例,说明变量的使用,看看如何编写。

    declare

    c_tax_rate number(3,2):=0.03;

    v_ename varchar2(5);

    v_sal number(7,2);

    v_tax number(7,2);

    begin

    select ename,sal into v_ename,v_sal from emp where empno=&no;

    v_tax:=v_sal*c_tax_rate;

    dbms_output.put_line('姓名是:'||v_ename||' 工资是:'||v_sal||' 所得税是:'||v_tax);

    B、使用%type类型

    对于上面的pl/sql块有一个问题:

    就是如果员工的姓名超过了5字符的话,就会有错误,为了降低pl/sql程序的维护工作量,可以使用%type属性定义变量,这样它会按照数据库列来确定你定义的变量的类型和长度。

    语法:标识符名 表名.列名%type;

    declear

    c_tax_rate number(3,2):=0.03;

    v_ename emp.ename%type;

    v_sal emp.sal%type;

    v_tax number(7,2);

    begin

    select ename,sal into v_ename,v_sal from emp where empno=&no;

    v_tax:=v_sal*c_tax_rate;

    dbms_output.put_line('姓名是:'||v_ename||' 工资是:'||v_sal||' 所得税是:'||v_tax);

    2、复合变量(composite)

    用于存储多个值的变量。主要包括这几种pl/sql记录、pl/sql表、嵌套表、varray。

    1、pl/sql记录

    类似于高级语言中的结构体,需要注意的是,当引用pl/sql记录成员时,必须要加记录变量作为前缀(记录变量.记录成员)。

    declare

    type emp_record_type is record(name emp.ename%type, salary emp.sal%type,title emp.job%type);

    sp_record emp_record_type;

    begin

    select ename,sal,job into sp_record from emp where empno=7788;

    dbms_output.put_line('员工名:'||sp_record.name);

    2、pl/sql表

    相当于高级语言中的数组,但是需要注意的是在高级语言中数组的下标不能为负数,而pl/sql是可以为负数的,并且表元素的下标没有限制。

    declare

    type sp_table_type is table of emp.ename%type index by binary_integer;

    sp_table sp_table_type;

    begin

    select ename into sp_table(0) from emp where empno=7788;

    dbms_output.put_line('员工名:'||sp_table(0));

    sp_table_type:是pl/sql表类型

    emp.ename%type:指定了表的元素的类型和长度

    sp_table:是pl/sql表变量

    sp_table(0):表示下标为0的元素

    3、参照变量

    概述:参照变量是指用于存放数值指针的变量,通过使用参照变量,可以使得应用程序共享相同对象,从而降低占用空间。在编写pl/sql程序时,可以使用游标变量(ref cursor)和对象类型变量(ref obj_type)两种参照变量类型。

    1、游标变量(ref cursor)

    使用游标时,当定义游标时不需要指定相应的select语句,但是当使用游标时(open时)需要指定select语句,这样一个游标就与一个select 语句结合了。

    请使用pl/sql编写一个块,可以输入部门号,并显示该部门所有员工姓名和他的工资

    declare

    type sp_emp_cursor is ref cursor;

    test_cursor sp_emp_cursor;

    v_ename emp.ename%type;

    v_sal emp.sal%type

    begin

    opent test_cursor for select ename,sal from emp where deptno=&no;

    fetch test_cursor into v_ename,v_sal;

    exit when test_cursor%notfound

    dbms_output.putline('姓名:'||v_ename||' 工资:'||v_sal);

    endloop;

    close test_cursor;

    九、控制结构

    概述:在任何计算机语言(C、Java、Pascal)都有各种控制语句(条件语句、循环结构、顺序控制结构),在pl/sql中也存在这样的控制结构。

    1、条件分支语句

    pl/sql中提供了三种条件分支语句。if-then、if-then-else、if-then-elsif-else。

    (1)简单的条件判断if-then

    案例:编写一个过程,可以输入一个雇员名,如果该雇员的工资低于2000,就给该雇员工资增加10%。

    create procedure IncreaseSal(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 sal=sal+sal*10% where ename=spName;

    end if;

    (2)二重条件分支if-then-else

    案例:编写一个过程,可以输入一个雇员名,如果该雇员的补助不是0,就在原来的基础上增加100;如果补助为0就把补助设为200。

    create procedure IncreaseComm(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;

    update emp set comm=200 where ename=spName;

    end if;

    (3)多重条件分支if-then-elsif-else

    案例:编写一个过程,可以输入一个雇员编号,如果该雇员的职位是PRESIDENT就给他的工资增加1000,如果该雇员的职位是MANAGER就给他的工资增加500,其他职位的雇员工资增加200。

    create procedure IncreaseSal(spNo number) is

    v_job emp.job%type;

    begin

    select job into v_job from emp where empno=spNo;

    if v_job='PRESIDENT' then

    update emp set sal=sal+1000 where empno=spNo;

    elsif v_job='MANAGER'

    update emp set sal=sal+500 where empno=spNo;

    update emp set sal=sal+200 where empno=spNo;

    end if;

    2、循环语句

    (1)基本循环

    loop是pl/sql中最简单的循环语句,这种循环语句以loop开头,以end loop结尾,这种循环至少会被执行一次。

    案例:编写一个过程,可输入用户名,并循环添加10个用户到Users表中,用户编号从1开始增加。

    create procedure AddUser(spName varchar2) is

    v_num number(2):=1;

    begin

    insert into Users values(v_num,spName);

    exit when v_num=10;

    v_num:=v_num+1;

    endloop;

    (2)While循环

    基本循环至少要执行循环体一次,而对于while循环来说,只有条件为true时,才会执行循环体语句,while循环以while 条件 loop开始,以end loop结束。

    编写一个过程,可输入用户名,并循环添加10个用户到Users表中,用户编号从11开始增加

    create procedure AddUser(spName varchar2) is

    v_num number(3):=11;

    begin

    while v_num<=20 loop

    insert into Users values(v_num,spName);

    v_num:=v_num+1;

    endloop;

    (3)for循环

    基本for循环的基本结构如下

    begin

    for i in reverse 1..10 loop

    insert into Users values(i,'Kevin');

    end loop;

    3、顺序控制语句

    (1)goto语句

    goto语句用于跳转到特定标号去执行有车,注意由于使用goto语句会增加程序的复杂度,并使得应用程序可读性变差,所以在一般应用开发时,建议大家不要使用goto语句

    基本语法如下:

    goto label:其中label是已经定义好的标号名。

    declare

    i number(4):=1;

    begin

    dbms_output.put_line("输出i='||i");

    if i=10 then

    goto end_loop

    end if;

    i:=i+1;

    endloop;

    <<end_loop>>

    dbms_output.put_line("循环结束");

    (2)null

    null语句不会执行任何操作,并且会直接将控制传递到下一条语句。使用null语句的主要好处是可以提高pl/sql的可读性。

    declare

    v_sal emp.sal%type;

    begin

    select sal into v_sal from emp where ename=spName;

    if v_sal<2000 then

    update emp sal=sal+sal*10% where ename=spName;

    null;

    end if;

    十、编写分页过程

    概述:分页时任何一个网站(bbs、网上商城、Blog)都会使用到的技术,因此学习pl/sql编程开发就一定要掌握该技术。

    案例:编写一个过程完成分页。

    --创建一个包,存放游标。

    create package ListPackage as

    type page_cursor is ref cursor;

    --开始编写分页的过程

    create procedure PagedList(

    tableName in varchar2, --要查询的表名

    sortColumn in varchar2, --欲排序的列名

    pagesize in number, --每页显示的记录数

    currentPage in number, --当前页号

    myRowCount out number, --表中总共的记录数

    myPageCount out number, --共有多少页

    p_cursor out ListPackage.page_cursor --游标变量

    v_sql varchar2(1000);

    v_begin number:=(currentPage-1)*pagesize+1;

    v_end number:=currentPage*pagesize;

    begin

    v_sql:='select * from(select *, rownum rn from (select * from '||tableName||' order by '||sortColumn||') t1 where rownum<='||v_end||') where rn>='||v_begin;

    open p_cursor for v_sql;

    --计算myRowCount和myPageCount

    v_sql:='select count(*) from '||tableName;

    execute immediate v_sql into myRowCount;

    if mod(myRowCount,pagesize)=0 then

    myPageCount:=myRowCount/pagesize;

    myPageCount:=myRowCount/pagesize+1;

    end if;

    close p_cursor;

    十一、例外处理

    1、例外的分类

    Oracle将例外分为预定义例外、非预定义例外和自定义例外三种。

    预定义例外:用于处理常见的Oracle错误。

    非预定义例外:用于处理预定义例外不能处理的例外。

    自定义例外:用于处理与Oracle错误无关的其他情况。

    2、处理预定义例外

    预定义例外时由pl/sql所提供的系统例外。当pl/sql应用程序违反了Oracle规定的限制时,则会隐含的触发一个内部例外。pl/sql为开发人员提供了二十多个预定义例外。我们给大家介绍常用的例外。

    (1)预定义例外case_not_found

    在开发pl/sql块中编写case语句时,如果在when子句中没有包含必须的条件分支,就会触发case_not_found的例外。

    create procedure sp_pro6(spno number) is

    v_sal emp.sal%type;

    begin

    select sal into v_sal from emp where empno=spno;

    when v_sal<1000 then

    update emp set sal=sal+100 where empno=spno;

    when v_sal<2000 then

    update emp set sal=sal+200 where empno=spno;

    end case;

    exception

    when case_not_found then

    dbms_output.put_line('case语句没有与'||v_sal||'相匹配的条件');

    (2)预定义例外cursor_already_open

    当从新打开已经打开的游标时,会隐含的触发例外cursor_already_open。

    declare

    cursor emp_cursor is select ename,sal from emp;

    begin

    open emp_cursor;

    for emp_record1 in emp_cursor loop

    dbms_output.put_line(emp_record1.ename);

    end loop;

    exception

    when cursor_already_open then

    dbms_output.put_line('游标已经打开');

    (3)预定义例外dup_val_on_index

    在唯一索引所对应的列上插入重复的值时,会隐含的触发例外dup_val_on_index例外。

    begin

    insert into dept values(10.'公关部','北京');

    exception

    when dup_val_on_index then

    dbms_output.put_line('在deptno列上不能出现重复值');

    (4)预定义例外invalid_cursor

    当试图在不合法的游标上执行操作时,会触发该例外。

    例如:视图从没有打开的游标提取数据,或是关闭没有打开的游标。则会触发该例外。

    declare

    cursor emp_cursor is select ename,sal from emp;

    emp_record emp_cursor%rowtype;

    begin

    fetch emp_cursor into emp_record;

    dbms_output.put_line(emp_record.ename);

    close emp_cursor;

    exception

    when invalid_cursor then

    dbms_output.put_line('请检查游标是否打开');

    (5)预定义例外invalid_number

    当输入的数据有误时,会触发该例外。

    案例:数字100写成了1oo就会触发该例外

    begin

    update emp set sal=sal+'1oo';

    exception

    when invalid_number then

    dbms_output.put_line('输入数字不正确');

    (6)预定义例外no_data_found

    下面是一个pl/sql块,当执行select into没有返回行,就会触发该例外。

    declare

    v_sal emp.sal%type;

    begin

    select sal into v_sal from emp where ename='&name';

    exception

    when no_data_found then

    dbms_output.put_line('不存在该员工');

    (7)预定义例外too_many_rows

    当执行select into语句时,如果返回超过了一行,则会触发该例外。

    declare

    v_ename emp.ename%type;

    begin

    select ename into v_ename from emp;

    exception

    when too_many_rows then

    dbms_output.put_line('返回了多行');

    (8)预定义例外zero_divide

    当执行除0操作时,则会触发给例外。

    (9)预定义例外value_error

    当在执行赋值操作时,如果变量的长度不足以容纳实际数据,则会触发该例外value_error。

    declare

    v_ename varchar2(5);

    begin

    select ename into v_ename from emp where empno=&no;

    dbms_output.put_line(v_ename);

    exception

    when value_error then

    dbms_output.put_line('变量尺寸不足');

    (10)其它预定义例外

    A、login_denide

    当用户非法登录时,会触发该例外。

    B、not_logged_on

    如果用户没有登录就执行dml操作,就会触发该例外。

    C、storage_error

    如果超出了内存空间或是内存被损坏,就触发该例外。

    D、timeout_on_resourece

    如果Oracle在等待资源时,出现超时就触发该例外。

    3、非预定义例外

    非预定义例外用于处理与预定义例外无关的Oracle错误,使用预定义例外只能处理21个Oracle错误,而当使用pl/sql开发应用程序时,可能会遇到其他的一些Oracle错误。比如在pl/sql快中执行dml语句时,违反了约束规定等等。在这样的情况下,也可以处理Oracle的各种例外。

    4、处理自定义例外

    预定义例外和非预定义例外都是Oracle错误相关的,并且处在的Oracle错误会隐含的触发相应的例外。而自定义例外与Oracle错误没有任何关联,它是由开发人员为特定情况所定义的例外。

    案例:请编写一个pl/sql块,接收一个雇员的编号,并给该雇员工资增加1000元,如果该雇员不存在请提示。

    create procedure IncreaseSal(spno number) is

    myException exception;

    begin

    update emp set sal=sal+100 where empno=spno;

    if sql%not_found then

    raise myException;

    end if;

    exception

    when myException then

    dbms_output.put_line('没有更新任何用户');

    十二、Oracle视图

    概述:视图是一个虚拟表,其内容由查询定义,同真实表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在,行和列数据来自有定义视图的查询所引用的表,并且在引用视图时动态生成。

    1、视图与表的区别

    A、表需要占用磁盘空间,视图不需要。

    B、视图不能添加索引。

    C、使用视图可以简化复杂查询。

    D、视图有利于提高安全性。

    2、创建视图

    create view 视图名 as select语句[with read only]

    3、创建或修改视图

    create or replace view 视图名 as select语句[with read only]

    4、删除视图

    drop view 视图名

    收藏于 2013-12-16
    文章优化有问题?点击这里反馈URL给我们




  • 相关阅读:
    ORACLE 定时执行存储过程
    Java 基于spring 暴露接口 供外部调用
    java 从jsp页面传集合给controller
    Java 后台验证的工具类
    Xcode12真机/模拟器运行项目非常慢的解决方式
    苹果手机系列 安全区高度/设置粗体高度不正常
    Xcode 官方下载地址
    OC UICollectionView 滚动完全显示item
    cocospod 更新到指定版本及其问题
    OC 一张图片填充满整个导航栏(包含X系列)
  • 原文地址:https://www.cnblogs.com/hijushen/p/4224730.html
Copyright © 2020-2023  润新知