一、概述

pl/sql (procedural lanaguage/sql)是 oracle 在标准 sql 上的扩展 。不仅允许嵌入sql 语言,还可以定义变量和常量,允许使用条件语句和循环语句,允许使用例外处理错误。

-- 可以用来编写过程,函数,和触发器

-- 上述对象是放在数据库中的  //数据库端

-- 过程和函数可以在java程序中调用 ,触发器只能被触发,不能被调用

优点:

1.提高程序性能

2.模块化的程序设计思想

3.减少网络传输流量

4.安全性高

5.能处理较复杂的sql操作

缺点:

1.移植性不好

2.可维护性差

3.不好调试

  1. //例子 创建存储过程
  2. create procedure sp_adduser is //可以写成 create or replace (如果存在就替换 )
  3. begin
  4. insert into userinfo(userName) values ('zhangsan');
  5. end;

如何调用?

exec 存储过程名  -> exec sp_adduser

二、pl-sql 的简单分类和编写规范

简单分类

1.过程(存诸过程)块(编程的基本单位)

2.函数

3.触发器

4.包

变量编写规范

注释 --    或   /*   */

变量 v_   // 比如  v_sal

常量 c_   // 比如  c_rate

游标 _cursor 为后缀  //比如 emp_cursor

例外 e_   //比如 e_xxxerror

块(block) 是pl/sql 的基本程序单元,编写pl/sql程序实际上就是编pl/sql块. 简单的功能可能只需一个块,但是如果复杂,可能在一个块中嵌套其他块。

块由三部分组成 定义部,执行部分,例外部分
如下

  1. declear //可选,比如定义常量,变量,游标,复杂数据类型等
  2. begin
  3. exception //可选
  4. end;
  1. //例一 只包扩执行部分的pl/sql块
  2. set serveroutput on //打开输出选项,如果是off,则不会输出,默认是off
  3. begin
  4. dbms_output.put_line('嘻嘻');
  5. end;
  6. //说明 dbms_output 是 oracle 提供的包(类似java中的类),该包中有一个过程叫 put_line
  1. //例二 包含定义部分和执行部分的pl/sql块
  2. declare
  3. v_ename varchar2(50) ; --定义字符串型变量,这个变量的长度要够
  4. begin
  5. select ename into v_ename from emp where empno =&no; -- // &no这种写法是让用户可以手动输入值
  6. dbms_output.put_line('员工姓名'||v_ename); - -// ||是连接字符
  7. end;
  1. //例三 将上例改为,连薪水也打印出来,包含例外处理
  2. declare
  3. v_ename varchar2(150) ;
  4. v_sal number(7,2);
  5. begin
  6. select ename,sal into v_ename ,v_sal from emp where empno =&no;
  7. dbms_output.put_line('员工姓名'||v_ename || '工资:'||v_sal);
  8.  
  9. exception //进行例外处理
  10. when no_data_found then
  11. dbms_output.put_line('没有查询到对应的数据');
  12. end;

说明 : 输入了不存在的员工号,会出错,要进行例外处理

oracle 预先定义了一些例外

NO_DATA_FOUND 就是找不到数据的时候出现的例外

预定义例外: INVALID_CURSOR,ZERO_DIVIDE,VALUE_ERROR,INVALID_NUMBER ....  //等共22种,都对应一个errorcod

过程

过程用于执行特定的操作,当建立过程的时候,即可指定输入参数(in) ,也可以指定输出参数 (out)

==通过输入参数,可以将数据传给过程的执行部分

==通过输出参数,可以将执行部分的搂据传给应用环境 (存储过程的调用者)

可以用 create procedure 创建过程

例子

编写过程,可以输入员工名,新工资,可以修改员工的工资

调用过程  //exec 过程名

在java程序中调用一个过程

  1. create procedure sp_01(p_name varchar2, p_sal number) is --//这里不用指定长度
  2. begin
  3. update emp set sal=p_sal where ename=p_name;
  4. end;

执行 exec sp_01('SCOTT',9090);

  1. //在java中调用
  2.  
  3. public static void test() {
  4. Connection conn = null;
  5. CallableStatement stm = null;
  6. try {
  7. conn = DBUtil.getConn();
  8. stm = conn.prepareCall("{call sp_01(?,?)}"); 如果是sa 登录 要写成 {scott.call sp_01(?,?)}
  9. stm.setString(1, "SCOTT");
  10. stm.setInt(2, 10900);
  11. stm.execute();
  12. System.out.println("---操作成功----");
  13. } catch (Exception ex) {
  14. ex.printStackTrace();
  15. } finally {
  16. DBUtil.close(null, stm, conn);
  17. }
  18. }

附: 驱动类名: oracle.jdbc.driver.OracleDriver ,连接字串 jdbc:oracle:thin:@localhost:1521:orcl

函数

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

函数一般只返回一个值

  1. //输入员工的姓名,返回他的年薪
  2. create function fun01(p_name varchar2)
  3. return number is -- 在函数头部必须包括 return 子句 ,number 表示返回的是数值类型
  4. totalsal number(8,2);
  5. begin
  6. select sal*12+nvl(comm,0)*12 into totalsal from emp where ename=p_name;
  7. return totalsal;
  8. end;

执行函数

  1. SQL> var result number;
  2. SQL> call fun01('SCOTT') into :result;
  1. //在java程序中调用
  2.  
  3. public static void test2(){
  4. Connection conn = null;
  5. CallableStatement stm = null;
  6. try {
  7. conn = DBUtil.getConn();
  8. stm=conn.prepareCall("{?=call fun01('SCOTT')}"); //fun01 是函数名,SCOTT是函数要求的参数,? 是返回值的占位符
  9. stm.registerOutParameter(1, java.sql.Types.VARCHAR); //声要接收返回值,1 代表第一个问号 java.sql.Types.VARCHAR 代表返回值的类型
  10. stm.execute();
  11.  
  12. String result= stm.getString(1); //取出返回值
  13. System.out.println("年薪是:"+result);
  14. } catch (Exception ex) {
  15. ex.printStackTrace();
  16. } finally {
  17. DBUtil.close(null, stm, conn);
  18. }
  19. }

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

1) 可以使用 create package 命令来创建包

  1. create package sp_package_01 is
  2. procedure sq_update_sal(name varchar2,newsal number); --//只有声明,没有实现
  3. function fun02(name varchar2) return number; --//这个函数有一个 number类型的返回值
  4. end;

包的规范只包含了过程和函数的说明,但没有实现

2) 建立包体  create package body 命令

  1. create package body sp_package_01 is
  2. procedure sq_update_sal(name varchar2,newsal number) is
  3. begin
  4. update emp set sal=newsal where ename=name; --//更新工资
  5. end;
  1. function fun02(name varchar2) return number is
  2. totalsal number(8,2);
  3. begin
  4. select sal*12+nvl(comm,0)*12 into totalsal from emp where ename=name;
  5. return totalsal;
  6. end;

//显示错误信息 show errors

如何调用包里的内容,要用包名,如果是其他方案的,要有方案名.

  1. //执行
  2. exec sp_package_01.sq_update_sal('SCOTT',5000);

变量-之标量

在编写pl/sql 的时候,可以定义变量和常量,包括

== 标量类型(scalar)

== 复合类型(composite)

== 参照类型(reference)

== lob (large object)  //大对象

标量(scalar)

1) 常用类型的标量的定义

标量主要用来放单个数据

如果要使用变量,要在定义部分定义

语法

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

identifier:名称

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

datatype: 数据类型

not null: 表示不能为空

default: 初值

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

例子

-- 定义一个变长字符串

v_empnam varchar2(10)

-- 定义一个小数  值在 -9999.99 - 9999.99 之间

v_sal number(6,2)

-- 定义一个小数,并给初值为 3.14

v_pai number(3,2) :=3.14     // := 赋值符号

-- 定义一个日期类型的变量

v_hiredate data

-- 定义一个布尔型变量,不能为空,初值为false

v_result boolean not null default false

2)标量的使用

例子 输入员工号,显示员工工资,姓名,个人所得税(税率 0.02)

  1. set serveroutput on ;
  2. declare
  3.  
  4. c_tax_rage number(3,2):=0.02 ; --//税率,是常量,必须给初值
  5.  
  6. v_ename varchar2(50);
  7.  
  8. v_sal number(8,2);
  9.  
  10. v_tax_sal number(8,2); --//应交的所得税
  11.  
  12. begin
  13.  
  14. select ename ,sal into v_ename,v_sal from emp where empno=&no;
  15.  
  16. v_tax_sal:=v_sal*c_tax_rage; --//所得税=工资* 税率
  17.  
  18. dbms_output.put_line('姓名'||v_ename||'税'||v_tax_sal);
  19.  
  20. end ;

3) 使用 %type 类型定义标量

上例存在一个问题

如果员工的姓名超过了50 ,会报错   字符串缓冲区太小

可以使用  %type  属性定义标量,它会根据你的数据库中列的长度和类型来定义标量

标识符名称 表名 列名   %type

比如上例中 可以    v_ename emp.ename%type

变量-之复合变量

复合类型变量(composite) 好比数组

用于存放多个值

-- pl/sql 记录

-- pl/sql 表名

-- 嵌套表

-- varry //动态数组

1) pl/sql 记录

类似高级语言中的结构体 ,当引用 pl/sql 记录成员时,必须要加记录变量做为前缀(记录变量.记录名)

  1. declare
  2. type emp_recorder_type is record --//声明一个复合类型变量
  3. (
  4. name emp.ename%type,
  5. salary emp.sal%type,
  6. title emp.job%type
  7. );
  8. sp_record emp_recorder_type; --//定义了一个复合类型的变量,名称是sp_record,类型是 emp_recorder_type
  9. begin
  10. select ename,sal,job into sp_record from emp where empno=7788;
  11. dbms_output.put_lne('员工名'||sp_record.name||'工资'||sp_record.salary||'工作'||sp_record.title);
  12. end;

2) pl/sql 表名

相当于数组 ,但它的下标可以负值,并且元素的下标没有限制

  1. declare
  2. type sp_table_type is table of emp.ename%type --//定义一个 sp_table_type 自定义类型,用于存放 emp.ename%type 类型的数据
  3. index by binary_integer ; --//让这个表的下标是按整数来排序的
  4.  
  5. sp_table sp_table_type; --//定义了一个 sp_table_type 类型的变量,名字是 sp_table
  6.  
  7. begin
  8. select ename into sp_table(0) from emp where empno='7788'; --//目前只放了一条数据,如果是多条会报错
  9. dbms_output.put_line('员工名'||sp_table(0)); --//这个下标是负数也可以
  10. end;

变量-之参照类型变量 (reference)

用于存放数值指针的变量,通过它可以使得应用程序共享相同的对象,降低占用空间。
有以下两种

游标类型 (ref cursor)

对象类型 (ref obj_type) //不讲

1) 参照类型  -- ref cursor 游标变量

定义游标

用的时候(open ),要指定select 语句,这样一个游标就和select语句关联了,需求 写一个pl/sql语句块,可以输入部门号,并显示该部门的所有员工姓名和工资。如果某个员工的工资低于5000,就增加10000 元。

  1. declare
  2. type sp_cursor is ref cursor ; --//定义一个游标类型叫 sp_cursor
  3. v_ename emp.ename%type;
  4. v_sal emp.sal%type;
  5. test_cursor sp_cursor; --//定义一个游标类型的变量,名叫 test_cursor
  6.  
  7. begin
  8. open test_cursor for select ename,sal from emp where deptno=&no; --//打开游标 ,要指定一个select语句
  9. loop
  10.  
  11. fetch test_cursor into v_ename,v_sal;
  12. exit when test_cursor % notfound;
  13. dbms_output.put_line(v_ename||v_sal);
  14. if v_sal<3000 then
  15. update emp set sal=v_sal+10000 where ename=v_ename;
  16. end if;
  17.  
  18. end loop;
  19. close test_cursor;
  20. end if;
    end;

控制结构语句

条件分支语句

if then

if then else

if then elsif else   //注意,不是elseif

循环语句

loop ... end loop

while ... loop     end loop

for

控制语句

goto 语句

null 语句

1)条件分支语句

== if then

编写一个过程,可以输入一个员工名,如果工资小于5000,则再扣3000

和上例相似

if v_sal<5000 then

update emp set sal=v_sal-3000 where ename=v_ename;

end if;

== if then else  //二重条件分支

输入一个员工名,如果补助不是0 就在原来的基础上增加100,如果为0 就把补助改成200

  1. create or replace procedure sp_02 (spName varchar2) is
  2.  
  3. v_comm emp.comm%type;
  4. begin
  5. select comm into v_comm from emp where ename=spName;
  6. if v_comm <>0 then
  7. update emp set comm=comm+100 where ename=spName;
  8. else
  9. update emp set comm=200 where ename=spName;
  10. end if;
  11. end;

执行: exec sp_02('SCOTT');

== 多重条件分支

if then elsif else

编写一个过程,可以输入一个员工编号,如果职位是 CLERK  给工资加 100 ,SALESMAN 给加工资 500,其他加 200

  1. create or replace procedure sp_03(sp_no number) is
  2. v_job emp.job%type;
  3.  
  4. begin
  5. select job into v_job from emp where empno=sp_no;
  6. if v_job='CLERK' then
  7. update emp set sal=sal+100 where empno=sp_no;
  8.  
  9. elsif v_job='SALESMAN' then
  10. update emp set sal=sal+500 where empno=sp_no;
  11.  
  12. else
  13. update emp set sal=sal+200 where empno=sp_no;
  14. end if;
  15.  
  16. end;

Java基础——Oracle(七)的更多相关文章

  1. Java实习生常规技术面试题每日十题Java基础(七)

    目录 1. Java设计模式有哪些? 2.GC是什么?为什么要有GC? 3. Java中是如何支持正则表达式. 4.比较一下Java和JavaSciprt. 5.Math.round(11.5) 等于 ...

  2. Java基础——Oracle(八)

    一.流程控制语句 1) 循环语句 == loop ..  end loop 简单的循环,至少被执行一次 create table userinfo (id number, name varchar2( ...

  3. Java基础——Oracle(六)

    一.数据字典和动态性能视图 数据字典: oracle中的重要组成部分,提供了数据库的一些系统信息,记录了数据库的系统信息,它是只读表和视图的集合,数据字典的所有者为 sys 用户.用户只能在数据字典上 ...

  4. Java基础——Oracle(四)

    一.Sql * plus 常用命令 1.关于登录,连接的几个命令 1) conn[nect] //例  conn system/manager 用法 conn 用户名/密码 @网络服务名 (as sy ...

  5. Java基础——Oracle(一)

    Oracle是目前最流行的数据库之一.功能强大,性能卓越.所以学起来比较困难.学习Oracle需要具备一定的基础.比如学习过一门编程语言,或者学过其他的数据库等,没有一些基础很难下手. 一.Oracl ...

  6. 构造方法,重载,static,math类(java基础知识七)

    1.构造方法概述和格式 * A:构造方法概述和作用     * 给对象的数据(属性)进行初始化 * B:构造方法格式特点     * a:方法名与类名相同(大小也要与类名一致)     * b:没有返 ...

  7. 夯实Java基础(七)——Static关键字

    1.static介绍 static关键字一直是各大企业中面试常常会问到的问题,主要考察面试者的基础是否扎实,下面来介绍一下static关键字. Java中static表示“全局”或者“静态”的意思,可 ...

  8. jar,war,ear区别及java基础杂七八

    jar,war,earqu区别 这三种文件都可以看作是java的压缩格式,其实质是实现了不同的封装: jar--封装类war--封装web站点ear--封装ejb.它们的关系具体为:jar:      ...

  9. java基础(七)面向对象(二)

    这里有我之前上课总结的一些知识点以及代码大部分是老师讲的笔记 个人认为是非常好的,,也是比较经典的内容,真诚的希望这些对于那些想学习的人有所帮助! 由于代码是分模块的上传非常的不便.也比较多,讲的也是 ...

随机推荐

  1. git(转载谢谢)

    Git可视化极简易教程 —— Git GUI使用方法   (新版的git默认已不能自行选择中文语言了) 前言 之前一直想一篇这样的东西,因为最初接触时,我也认真看了廖雪峰的教程,但是似乎我觉得讲得有点 ...

  2. git 命令(基础篇)的本质理解

    主要命令 1. 提交,git commit 本质:创建一个节点(node),标志了当前位置(node)与以前的node存在不同之处,如下图中的 c0 <-- c1 <-- c2 等等 图中 ...

  3. SQL Server 最大并行度

    一.概念 1.关联掩码(affinitymask) 为了执行多任务,MicrosoftWindows2000和WindowsServer2003有时会在不同的处理器之间移动进程线程.虽然从操作系统方面 ...

  4. 异步请求获取JSON数据

    json格式的数据广泛应用于异步请求中前后端的数据交互,本文主要介绍几种使用场景和使用方法. <script type="text/javascript"> funct ...

  5. 部署GitLab代码托管仓库

    GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,GitLab是使用Ryby开发的一个开源的版本管理系统,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私 ...

  6. Java中的代理机制

    Java的三种代理模式 代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能. 简言之,代理模 ...

  7. [CocoaPods]CocoaPods安装详解

    安装CocoaPods之前先安装ruby: 1.安装ruby ruby官网rubygems.org已被屏蔽,替换当前镜像是否为国内镜像. $gem sources --add https://gems ...

  8. 参考信息 - Serverless

    初见 Serverless的本质是什么? 看懂 Serverless,这一篇就够了 关于「Serverless」的完整指南:你知道和不知道的 了解 7个开源平台,入门无服务器计算

  9. laravel5实现第三方登录(微信)

    背景 最近手头一个项目需要实现用户在网站的第三方登录(微信和微博),后端框架laravel5.4. 实现过程以微信网页版第三方登录,其他于此类似,在此不做重复. 准备工作 网站应用微信登录是基于OAu ...

  10. [EXP]CVE-2018-2628 Weblogic GetShell Exploit

    漏洞简介 漏洞威胁:RCE--远程代码执行 漏洞组件:weblogic 影响版本:10.3.6.0.12.1.3.0.12.2.1.2.12.2.1.3 代码: # -*- coding: utf-8 ...