一、控制结构

  控制结构包括:判断语句(条件分支语句)、循环语句、顺序控制语句三种。

  1、条件分支语句

  • if--then:简单条件判断

    --编写一个过程,可以输入一个雇员名,如果该雇员名的工资低于2000,就给该雇员工资增加10%
    create or replace procedure pro_addSal(v_ename varchar2) is
    --定义变量
    v_sal emp.sal%type;
    begin
    select sal into v_sal from emp where ename=v_ename;
    --判断
    if v_sal<2000 then
    update emp set sal=sal+sal*0.1 where ename=v_ename;
    end if;
    end;
    /
  • if--then--else:二重条件分支
    --编写一个过程,可以输入一个雇员名,如果该雇员名的工资低于2000,就给该雇员工资增加10%,否则减少10%
    create or replace procedure pro_addSal(v_ename varchar2) is
    --定义变量
    v_sal emp.sal%type;
    begin
    select sal into v_sal from emp where ename=v_ename;
    --判断
    if v_sal<2000 then
    update emp set sal=sal+sal*0.1 where ename=v_ename;
    else
    update emp set sal=sal-sal*0.1 where ename=v_ename;
    end if;
    end;
    /
  • if--then--elsif--else:多重条件分支
    create or replace procedure pro_addSal(eNo number) is
    v_job emp.job%type;
    begin
    select job into v_job from emp where empno=eNo;
    if v_job='PRESIDENT' then
    update emp set sal=sal+1000 where empno=eNo;
    elsif v_job='MANAGER' then
    update emp set sal=sal+500 where empno=eNo;
    else
    update emp set sal=sal+200 where empno=eNo;
    end if;
    end;
    /

  2、循环语句

  • loop循环:pl/sql中最简单的循环语句,以loop开头,以exit()作为结束判断语句,以end loop结尾。(至少循环一次)

    --编写一个过程,输入用户名,并循环添加10个用户到users表中
    create table users(userId number(5),userName varchar(20));--为了后面操作先创建一个users表
    create or replace procedure pro_addUser(eName varchar2) is
    --定义变量
    v_num number:=1;
    begin
    loop
    insert into users values(v_num,eName);
    exit when v_num=10;--判断退出条件
    v_num:=v_num+1;--自增
    end loop;
    end;
    /
  • while循环:其实就是使用while语句来代替loop循环的exit语句。
    --编写一个过程,删除users表中的编号1—10的个用户
    --用户编号从1开始增加。
    create or replace procedure pro_delUser is
    --定义变量
    v_num number:=1;
    begin
    while v_num<=10 loop
    delete from users where userId=v_num;
    v_num:=v_num+1;--自增
    end loop;
    end;
    /
  • for循环:自带变量和循环退出条件
    create or replace procedure pro_addUser is
    begin
    for i in 1..10 loop
    insert into users values(i,'lucy');
    end loop;
    end;
    /

  3、顺序控制语句

  • goto语句:用于跳转到特定标号去执行语句。注:由于使用gogo语句会增加程序的复杂性,并使得应用程序可读性变差,因此建议不要使用goto语句。
    语法:goto lable,其中lable是已经定义好的标号名,如<<标记名>>,<<>>是标记符号,常用来跳出循环。

    --循环输出i=1..10,最后跳出循环后打印“循环结束”
    declare
    i int:=1;
    begin
    loop
    dbms_output.put_line('i='||i);
    if i=10 then
    goto end_loop;
    end if;
    i:=i+1;
    end loop;
    <<end_loop>>
    dbms_output.put_line('循环结束');
    end;
    /
  • null语句:null语句不会执行任何操作,并且会直接将控制传递到下一条语句。(类似Java中的continue的用法)
    declare
    v_sal emp.sal%type;
    v_ename emp.ename%type;
    begin
    select ename,sal into v_ename,v_sal from emp where empno=&no;
    if v_sal<3000 then
    update emp set comm=sal*0.1 where ename=v_ename;
    else
    null;
    end if;
    end;
    /

二、使用Java程序调用存储过程

  1、无返回值的存储过程

  创建一个表book,表结构如下:

   

  • create table book(bId number(4) primary key,bName varchar(30) not null,publisher varchar(30));

  编写一个过程,向book表添加书籍信息,要求可以通过java程序调用该过程:

  • 使用命令行创建:

    create or replace procedure pro_addBook(bookId number,bookName varchar2,pub varchar2) is
    begin
    insert into book values(bookId,bookName,pub);
    end;
    /
  • 使用Java调用无返回值的过程:
     package test;
    import java.sql.CallableStatement;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException; import org.junit.Test; /**
    * 使用java调用Oracle创建的过程pro_addBook
    */
    public class callPro_addBook {
    @Test
    public void test(){
    Connection conn = null;
    CallableStatement cs = null;
    try{
    //连接数据库
    Class.forName("oracle.jdbc.driver.OracleDriver");
    conn = DriverManager.getConnection(
    "jdbc:oracle:thin:@192.168.183.1:1521:orcl","scott","tiger");
    //获得执行对象
    cs = conn.prepareCall("{call pro_addBook(?,?,?)}");
    //传参
    cs.setInt(1, 1001);
    cs.setString(2, "五年模拟三年高考");
    cs.setString(3, "教育出版社");
    //执行
    cs.execute();
    }catch(Exception e){
    e.printStackTrace();
    }finally{
    try {
    cs.close();
    conn.close();
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }
    }
    }

    callPro_addBook

  2、有返回值的存储过程(返回若干值)

  编写一个过程,要求输入book表的书号就返回书籍信息:书名和出版社

  • 使用命令行创建过程:

    create or replace procedure pro_showBook
    (bookId in number,bookName out varchar2,pub out varchar2) is
    begin
    select bName,publisher into bookName,pub from book where bId=bookId;
    end;
    /
  • 使用Java调用返回值是若干数据的过程
     package test;
    import java.sql.CallableStatement;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException; import org.junit.Test; /**
    * 使用java调用Oracle创建的过程pro_addBook
    */
    public class callPro_showBook {
    @Test
    public void test(){
    Connection conn = null;
    CallableStatement cs = null;
    try{
    //连接数据库
    Class.forName("oracle.jdbc.driver.OracleDriver");
    conn = DriverManager.getConnection(
    "jdbc:oracle:thin:@192.168.183.1:1521:orcl","scott","tiger");
    //获得执行对象
    cs = conn.prepareCall("{call pro_showBook(?,?,?)}");
    //传入参数
    cs.setInt(1, 1001);
    cs.registerOutParameter(2, oracle.jdbc.OracleTypes.VARCHAR );
    cs.registerOutParameter(3, oracle.jdbc.OracleTypes.VARCHAR );
    //执行
    cs.execute();
    //获取out参数
    String bookName = cs.getString(2);
    String pub = cs.getString(3);
    System.out.println("书名:"+bookName);
    System.out.println("出版社:"+pub);
    }catch(Exception e){
    e.printStackTrace();
    }finally{
    try {
    cs.close();
    conn.close();
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }
    }
    }

    callPro_showBook

  3、有返回值的存储过程(返回一个列表)

  为了方便说明,我们再往book表中添加几条数据:

  

  现在的需求是:创建一个过程,要求返回指定出版社如“知乎周刊”出版的书籍信息。

    如表所示,返回结果是三本书,而这种查询结果集我们一般放在一个list即列表中,而在oracle在接受返回值时需要使用包package,并用游标来进行参数输出:

  • --建立包,在该包中,定义一个游标类型test_cursor
    create or replace package testpackage as
    type test_cursor is ref cursor;
    end;
    /
  • 使用命令行创建过程:
    create or replace procedure pro_showPubBook
    (pub in varchar2,my_cursor out testpackage.test_cursor) is
    begin
    open my_cursor for select * from book where publisher=pub;
    end;
    /
  • 使用Java调用返回值是列表的过程:
     package test;
    import java.sql.CallableStatement;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException; import org.junit.Test; /**
    * 使用java调用Oracle创建的过程pro_addBook
    */
    public class callPro_showPubBook {
    @Test
    public void test(){
    Connection conn = null;
    CallableStatement cs = null;
    try{
    //连接数据库
    Class.forName("oracle.jdbc.driver.OracleDriver");
    conn = DriverManager.getConnection(
    "jdbc:oracle:thin:@192.168.183.1:1521:orcl","scott","tiger");
    //获得执行对象
    cs = conn.prepareCall("{call pro_showPubBook(?,?)}");
    //传入参数
    cs.setString(1, "知乎周刊");
    cs.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR );//游标类型
    //执行
    cs.execute();
    //获得结果集
    ResultSet rs = (ResultSet) cs.getObject(2);
    System.out.println("知乎周刊出版社书籍:");
    if(rs!=null)
    while(rs.next()){
    System.out.println("书号:"+rs.getInt(1)+" "+"书名:《"+rs.getString(2)+"》");
    }
    else
    System.out.println("暂无书籍");
    }catch(Exception e){
    e.printStackTrace();
    }finally{
    try {
    cs.close();
    conn.close();
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }
    }
    }

    callPro_showPubBook

三、分页编程

  案例:编写一个存储过程,要求可以输入表名、每页显示记录数、当前页,返回总记录数、总页数和返回的结果集。

  1、使用rownum分页查询

  • select * from emp;
    select t1.*,rownum rn from (select * from emp) t1;
    select t1.*,rownum rn from (select * from emp) t1 where rownum<=10;
    select * from (select t1.*,rownum rn from (select * from emp) t1 where rownum<=10) where rownum>=6;

  2、编写分页的存储过程

  • --编写分页的存储过程
    create or replace procedure fenye
    (tableName in varchar2,--in表名
    myPageSize in number,--in记录数
    pageNow in number,--in当前页
    myRows out number,--out总记录数
    myPageCount out number,--out总页数
    p_cursor out testpackage.test_cursor--out结果集
    )is v_sql varchar2(500);--定义sql语句
    v_begin number:=(pageNow-1)*myPageSize+1;--定义起始页
    v_end number:=pageNow*myPageSize;--定义尾页 begin
    --执行分页查询语句
    v_sql:='select * from (select t1.*,rownum rn from (select * from '||tableName||
     ') t1 where rownum<='||v_end||') where rn>='||v_begin;
    --把游标和sql语句关联
    open p_cursor for v_sql;
    --计算myRows
    v_sql:='select count(*) from '||tableName;
    execute immediate v_sql into myRows;
    --计算myPageCount
    if mod(myRows,myPageSize)=0 then
    myPageCount:=myRows/myPageSize;
    else
    myPageCount:=myRows/myPageSize+1;
    end if;end;
    /

  3、使用Java调用分页过程

  •  import java.sql.CallableStatement;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet; public class Test {
    public static void main(String[] args) {
    // TODO Auto-generated method stub
    Connection ct = null;
    CallableStatement cs = null;
    try {
    Class. forName("oracle.jdbc.driver.OracleDriver");
    ct = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl", "scott", "***" ); cs = ct.prepareCall( "{call fenye(?,?,?,?,?,?)}"); // 赋值
    cs.setString(1, "emp");
    cs.setInt(2, 5);
    cs.setInt(3, 1); // 注册总记录数
    cs.registerOutParameter(4, oracle.jdbc.OracleTypes.INTEGER );
    // 注册总页数
    cs.registerOutParameter(5, oracle.jdbc.OracleTypes.INTEGER );
    // 注册返回的结果集
    cs.registerOutParameter(6, oracle.jdbc.OracleTypes.CURSOR ); cs.execute();
    // 取出总记录数
    int rowNum = cs.getInt(4);
    // 取出总页数
    int pageCount = cs.getInt(5);
    ResultSet rs = (ResultSet) cs.getObject(6); // 显示
    System. out.println( "rowNum=" + rowNum);
    System. out.println( "pageCount=" + pageCount); while ( rs.next()) {
    System. out.println( "编号:" + rs .getInt(1) + ",姓名:" + rs .getString(2));
    }
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } finally {
    try {
    // 关闭资源
    cs.close();
    ct.close();
    } catch (Exception e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
    }
    }
    }
    }

  

四、例外处理

  1、分类

  • 预定义例外:用于处理常见的oracle错误。
  • 非预定义例外:用于处理与预定义例外不能处理的例外。
  • 自定义例外:用于处理与oracle错误无关的其他情况。

  2、一个简单的例外处理

  编写一个过程,可接收雇员的编号,并显示该雇员的姓名。如果输入的雇员编号不存在,如何处理?

  • --例外
    declare
    v_ename emp.ename%type;
    begin
    select ename into v_ename from emp where empno=&no;
    dbms_output.put_line('名字:'||v_ename);
    exception when no_data_found then
    dbms_output.put_line('编号不存在,请重新输入!');
    end;
    /

  3、预定义例外

  由pl/sql所提供的系统例外。当pl/sql应用程序违反了oracle规定的限制时,则会隐含触发一个内部例外。pl/sql为开发人员提供了20多个预定义例外。

  •  case_not_found:when子句中没有包含必须的条件分支,就会触发case_not_found的例外。

    --case_not_found
    create or replace procedure sp_pro11(spno number) is
    v_sal emp.sal%type;
    begin
    select sal into v_sal from emp where empno=spno;
    case
    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||'相匹配的条件');
    end;
    /
  • cursor_already_open当重新打开已经打开的游标时,会隐含触发例外cursor_already_open。
    --cursor_already_open
    declare
    cursor emp_cursor is select ename,sal from emp;
    begin
    open emp_cursor;
    for emp_reacord1 in emp_cursor loop
    dbms_output.put_line(emp_record1.ename);
    end loop;
    exception
    when cursor_already_open then
    dbms_output.put_line('游标已经打开');
    end;
    /
  • dup_val_on_index:在唯一索引所对应的列上插入重复的值时,会隐含触发例外dup_val_on_index。
  • invalid_cursor:当试图在不合法的有表上执行操作时,会触发该例外。例如:试图从没有打开的游标提取数据,或是关闭没有打开的游标,则会触发该例外。
  • invalid_number当输入的数据有误时,会触发该例外。数字100写成了1oo就会触发该例外。
  • no_data_found当执行select into没有返回值时,就会触发该例外。
    --no_data_found
    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( '不存在该员工' );
    end;
  • too_many_rows执行select into语句时,如果返回超过了一行,则会触发该例外。
    --too_many_rows
    declare
    v_ename emp.ename%type;
    begin
    select ename into v_ename from emp;
    exception when too_many_rows then
    dbms_output.put_line('返回了多行');
    end;
    /
  • zero_divide当执行除法运算时,如果分母为0,则会触发该例外。
  • value_error在执行赋值操作时,如果变量的长度不足以容纳实际数据,则会触发该例外value_error。
  • login_denide:用户非法登录。
  • not_logged_on:用于未登录就执行dml操作。
  • storage_error:超出了内存空间或是内存被损坏。
  • timeout_on_resource:oracle在等待资源时,出现超时。

  4、非预定义例外

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

  5、自定义例外

  自定义例外与oracle错误没有任何关联,是由开发人员为特定情况所定义的例外。编写一个pl/sql块,接收一个雇员的编号,并给该雇员工资增加1000元,如果该雇员不存在,请提示。

--自定义例外
create or replace procedure ex_test(spNo number) is
--定义一个例外
myex exception;
begin
update emp set sal=sal+100 where empno=spNo;
if sql%notfound then
raise myex;--触发例外myex
end if;
exception
when myex then
dbms_output.put_line('没有更新任何例外');
end;
/
--说明:sql%notfound返回的数据类型是一个布尔值。布尔值与前一条sql语句相关。当最近的一条sql语句没有操作任何行的时候,返回true。否则返回false。

五、Oracle视图View

  1、概念

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

  2、视图与表的区别

  • 表需要占用磁盘空间,视图不占用。
  • 视图不能添加索引。
  • 使用视图可以简化复杂查询:比如学生选课系统。
  • 视图有利于提高安全性:比如不同用户查看不同视图。

  3、创建视图

  create or replace view 视图名 as select语句 [with read only]
  • --创建视图,把emp表的sal<1000的雇员映射到该视图
    create view myview as select * from emp where sal<1000;

  4、删除视图

  drop view 视图名;

  5、简单地使用视图

  比如说有表图书book(id,name,prise....)读者reader(id.....)借阅关系 borrow( bookid,readerid,date)。

  如果要查询读者借阅情况,我们需要多表查询比较麻烦,但是我们可以建立个视图,view1:

  • select * from book,reader,borrow where book.id=bookid and reader.id=readerid

    这样只要查询select * from view1 就可以看到谁借了什么书了,包括所有的详细内容。

Oracle实战笔记(第七天)之PL/SQL进阶的更多相关文章

  1. Oracle实战笔记(第六天)之PL/SQL基础

    一.PL/SQL介绍 1.概念 PL/SQL也是一种程序语言,叫做过程化SQL语言(Procedural Language/SQL).PL/SQL是Oracle数据库对SQL语句的扩展.在普通SQL语 ...

  2. oracle学习笔记(十六) PL/SQL 异常和goto语句

    PL/SQL 异常和goto语句 异常 预定义异常 oracle常见预定义异常: 错误号 异常错误信息名称 说明 ORA-0001 DUP_VAL_ON_INDEX 试图破坏一个唯一性限制 ORA-0 ...

  3. oracle学习笔记(十五) PL/SQL语法结构以及使用

    PL/SQL 简介 PL/SQL 是过程语言(Procedural Language)与结构化查询语言(SQL)结合而成的编程语言. PL/SQL 是对 SQL 的扩展. 支持多种数据类型,如大对象和 ...

  4. oracle学习笔记(十八) PL/SQL 游标

    游标 说明 查询结果的光标,相当于java中的一个迭代器,方便遍历操作 可使用的属性 %FOUND SQL语句查询或影响了一行或多行时为 TRUE.如:mycursor%FOUND %NOTFOUND ...

  5. pl/sql进阶--例外处理

    在pl/sql的执行过程中发生异常时系统所作的处理称为一个例外情况(exception).通常例外情况的种类有三种: 1.预定义的oracle例外情况oracle预定义的例外情况大约有24个,对于这种 ...

  6. pl/sql进阶一控制结构

    在任何计算机语言(c,java,c#,c++)都有各种控制语句(条件语句,循环结构,顺序控制结构…),在pl/sql中也存在这样的控制结构. 在本部分学校完毕后,希望大家达到: 1)使用各种if语句 ...

  7. Oracle实战笔记(第一天)

    导读 笔记内容来自韩顺平老师的视频<玩转Oracle实战教程>,可以结合笔记进行观看.第一天视频中还有Oracle的介绍和安装等内容,很容易搜索到,这里就不再进行总结. 目录 1.命令行工 ...

  8. Oracle 学习笔记 (七)

    一.数据库的启动 启动数据库的三个阶段: nomount, mount,open mount 阶段:. 1.读参数文件 2.分配内存 3.启动后台进程 4.初始化部分v$视图 mount 阶段: 读参 ...

  9. oracle 11g 64w 用32位的pl/sql

    1.  下载64位Oracle,解压两文件,解压完成后将文件合并,安装: 2.  下载PL/SQL,安装: 3.  下载instantclient-basic-win32-11.2.0.1.0.zip ...

随机推荐

  1. hbase (local mode) remote access

    如果初学hbase,没必要弄一个集群,hbase的local mode够用了. 这里写一个简单的教程.适用于初学hbase,想要用代码访问hbase的童鞋们. 目录: 0. 准备 1).  开发环境 ...

  2. 【矩阵快速幂】bzoj1297 [SCOI2009]迷路

    1297: [SCOI2009]迷路 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1407  Solved: 1007[Submit][Status ...

  3. centos设置程序开机自启或禁止加载

    1. 可以直接把需要启动的脚本写到/etc/rc.d/rc.local文件里,例如 vim /etc/rc.d/rc.local /usr/local/apache/bin/apachectl sta ...

  4. <The Art of Readable Code> 笔记二 (下)

    第1章  封装信息到名字 (Packing information into names) 4  附加额外信息 1)  encode value type 对于某些变量,附加额外的信息可以让人更好的理 ...

  5. 【SmartOS】轻量级多任务调度系统

    SmartOS是一个完全由新生命团队设计的嵌入式操作系统,主要应用于智能家居.物联网.工业自动化控制等领域. ARM Cortex-M系列微处理器几乎全都做成单核心,对于业务逻辑较复杂的物联网就显得难 ...

  6. HDU 1002 A + B Problem II(高精度加法(C++/Java))

    A + B Problem II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  7. [bzoj2665] [cqoi2012]编号

    首先有一个直观暴力的想法.. 枚举每个数,如果这个数可行的话,就加进答案里,然后把和它超过4个位置相同的数去掉. 然后正解真的是这个>_< 假设取到了数x,只要和x有5位相同的数就可以排除 ...

  8. c语言变量类型联想

    int float char *(指针) 已经定义:单个变量 单个相同类型在内存中顺序存放:数组 不同单个类型在内存中顺序存放:结构体 不同类型在内存中自由存放:链表 其中结构体与链表类型需运用时提前 ...

  9. git工作流程一览

    Git是分布式版本控制系统,没有中央服务器,每个人的电脑就是一个完整的版本库,工作的时候不需要联网了,因为版本都在自己电脑上.协同的方法是这样的:比如说自己在电脑上改了文件A,其他人也在电脑上改了文件 ...

  10. 使用Android Studio过程中,停留在“Building ‘工程名’ Gradle project info”的解决方法

    http://www.loverobots.cn/in-the-process-of-using-studio-android-the-solution-of-the-project-info-gra ...