十三、存储过程和存储函数
1、掌握存储过程(相当于建立一个函数或者方法体,然后通过外部对其调用)
指存储在数据库中供所有程序调用的子程序叫做存储过程或存储函数。

相同点:
完成特定功能的程序
区别:
是否用return语句返回值

(1)创建和使用存储过程
用create procedure命令建立存储过程和存储函数

语法:
create or replace procedure 过程名(参数列表) as PL/SQL 子程序体(说明部分);

事例:
(a)打印一个存储过程:打印HelloWorld(无参数)
create or replace procedure sayhelloworld
as
--说明部分
begin
dbms_output.put_line('Hello World !!!');
end;
/
在编译器左边的过程里形成大写的SAYHELLOWORLD

对其调用:
方法一:
execute 简写为exec sayhelloworld();
方法二:
begin
sayhelloworld();
sayhelloworld();
end;
/

(b)带参数的存储过程
事例:为指定的员工,涨100块钱的工资,并且打印涨前和涨后的薪水
思路:1、创建一个带参数的存储过程
2、给指定的员工涨100块钱的工资,并且打印涨前和涨后的薪水
create or replace procedure raisesalary(eno in number)
as
--定义一个变量保存涨钱的薪水
psal emp.sal%type;
begin
--得到员工涨前的薪水
select sal into psal from emp where empno=eno;

--给员工涨100
update emp set sal=sal+100 where empno=eno;
dbms_output.put_line('涨前薪水 :'||psal||'涨后薪水 :'||(psal+100));

--是否需要commit?
--注意:一般不在存储过程或者存储函数中,commit和rollback.原则不绝对
end;
/

如何调用:
begin
raisesalary(7839);
raisesalary(7566);
commit;
end;

如何调试
注意:不推荐远程调试,推荐本地调试
过程-->右键-->编译以进行调试

设置断点
select sal into psal from emp where empno=eno;
点击瓢虫调试
更改值 ENO := 7839; 点击确定
授权
系统认证登录:sqlplus / as sysdba
grant DEBUG CONNECT SESSION ,DEBUG ANY PROCEDURE to scott;
右键点击检测psal
调试
点击F8

2、掌握存储函数
函数为一命名的存储程序,可带参数,并返回一计算值.
函数和过程的结构类似,但必须有一个return子句,用于返回函数值.

(1)创建存储函数的语法
create or replace function 函数名(参数列表)
return 函数值类型
as
PL/SQL子程序体;

事例:查询某个员工的年收入
create or replace function queryempincome(eno in number)
return number
as
--定义变量保存员工的薪水和奖金
psal emp.sal%type;
pcomm emp.comm%type;
begin
--得到该员工的月薪和奖金
select sal,comm into psal,pcomm from emp where empno=eno;
--直接返回年收入
return psal*12+nvl(pcomm,0);
end;
/

set linesize 200
select * from emp;

调用存储函数

(2)in和out参数
一般来讲,存储过程和存储函数的区别在于存储函数可以有一个返回值,而存储过程没有返回值.

存储过程和存储函数都可以有out参数
存储过程和存储函数都可以有多个out参数
存储过程可以通过out参数来实现返回值

什么时候用存储过程/存储函数?
原则:
-- 如果只有一个返回值,用存储函数,否则,就用存储过程.

----out参数,查询某个员工姓名,月薪和职位
create or replace procedure queryempinform(eno in number, pename out varchar2,psal out number,pjob out varchar2)
as
begin
--得到该员工的姓名,月薪和职位
select ename,sal,empjob into pename,psal,pjob from emp where empno=eno;
end;
/

思考:(1)查询某个员工的所有信息---->out参数太多了
set linesize 80
desc emp
(2)查询某个部门中所有员工的所有信息--->out中返回集合

(3)在应用程序中访问存储过程和存储函数
(a)访问存储过程
public class JdbcUtils {
private static String url = "jdbc:oracle:thin:@localhost:1521:orcl";
private static String username = "scott";
private static String password = "tiger";
private static Connection conn;

public static Connection getConnection() {
conn = null;
try {
conn = DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("oracle连接获取失败");
}
return conn;
}

// 关闭连接对象
public static void close(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("oracle连接关闭失败");
}
}
}

public static void close(Statement stmt) {
if (stmt != null) {
try {
stmt.close();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("oracle连接关闭失败");
}
}
}

public static void close(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("oracle连接关闭失败");
}
}
}
}

public class TestProcedure {

@Test
public void testProcedure() {
String sql = "{call queryempinform(?,?,?,?)}";
Connection conn = null;
CallableStatement call = null;

try {
// 得到一个连接
conn = JdbcUtils.getConnection();
// 通过连接创建出statement
call = conn.prepareCall(sql);

//对于in参数,赋值
call.setInt(1, 7839);
//对于out参数,申明
call.registerOutParameter(2, OracleTypes.VARCHAR);
call.registerOutParameter(3, OracleTypes.NUMBER);
call.registerOutParameter(4, OracleTypes.VARCHAR);

//执行调用
call.execute();

//取出结果
String name =call.getString(2);
double sal =call.getDouble(3);
String job =call.getString(4);
System.out.println(name+"\t"+sal+"\t"+job);

} catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtils.close(conn);
JdbcUtils.close(call);
}
}

}
(b)访问存储函数
public class TestFunction {

@Test
public void testFunction() {
String sql = "{?=call queryempincome(?)}";
Connection conn = null;
CallableStatement call = null;

try {
// 得到一个连接
conn = JdbcUtils.getConnection();
// 通过连接创建出statement
call = conn.prepareCall(sql);

// 对于输出参数,申明
call.registerOutParameter(1, OracleTypes.NUMBER);

// 对于参数赋值
call.setInt(2, 7839);

// 执行调用
call.execute();

// 取出结果

double income = call.getDouble(1);

//打印结果集
System.out.println("年收入:" + income);

} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
JdbcUtils.close(call);
}
}
}

(4)在out参数中使用光标

(a)申明包结构
(b)包头
(c)包体

事例:查询某个部门中所有员工的所有信息

包头:
create or replace package mypackage as
--type自定义类型empcursor
type empcursor is ref cursor;
procedure queryEmpList(dno in number,empList out empcursor);
end mypackage;
*****包体需要实现包头中生命的所有方法*******

操作:
程序包----->右键--->新建程序包--->包名设置mypackage--->确定--->编译--->ctril+s执行

包体:
create or replace package body mypackage as

procedure queryEmpList(dno in number,empList out empcursor) as
begin

open empList for select * from emp where deptno =dno;
end queryEmpList;
end mypackage;

操作:
选中mypackage-->右键-->创建主体--->编译--->ctril+s执行

查看包:
desc mypackage

注意:需要带上包名访问

(5)在应用中访问包中的存储过程
public class TestMypackage {
@Test
public void testMypackage() {
String sql = "{call MYPACKAGE.queryEmpList(?,?)}";
Connection conn = null;
CallableStatement call = null;
ResultSet rs = null;

try {
// 得到一个连接
conn = JdbcUtils.getConnection();
// 通过连接创建出statement
call = conn.prepareCall(sql);

// 对于参数赋值
call.setInt(1, 10);

// 对于输出参数,申明
call.registerOutParameter(2, OracleTypes.CURSOR);

// 执行调用
call.execute();

// 取出该部门的所有员工信息

rs = ((OracleCallableStatement) call).getCursor(2);
while (rs.next()) {
// 该员工的员工号/薪水/职位
int empno =rs.getInt("empno");
String name =rs.getString("ename");
double salary = rs.getDouble("sal");
String job = rs.getString("empjob");
System.out.println(empno +"\t"+name+"\t"+salary+"\t"+job);

}

} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
JdbcUtils.close(call);
JdbcUtils.close(rs);
}
}
}

Oracle学习笔记(十二)的更多相关文章

  1. Oracle学习笔记十二 子程序(存储过程、自定函数)和程序包

    子程序 子程序:命名的 PL/SQL 块,编译并存储在数据库中.   子程序的各个部分: 1.声明部分 2.可执行部分 3.异常处理部分(可选) 子程序的分类: 1.过程 - 执行某些操作 2.函数 ...

  2. python3.4学习笔记(十二) python正则表达式的使用,使用pyspider匹配输出带.html结尾的URL

    python3.4学习笔记(十二) python正则表达式的使用,使用pyspider匹配输出带.html结尾的URL实战例子:使用pyspider匹配输出带.html结尾的URL:@config(a ...

  3. Go语言学习笔记十二: 范围(Range)

    Go语言学习笔记十二: 范围(Range) rang这个关键字主要用来遍历数组,切片,通道或Map.在数组和切片中返回索引值,在Map中返回key. 这个特别像python的方式.不过写法上比较怪异使 ...

  4. java jvm学习笔记十二(访问控制器的栈校验机制)

    欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 本节源码:http://download.csdn.net/detail/yfqnihao/4863854 这一节,我们 ...

  5. (C/C++学习笔记) 十二. 指针

    十二. 指针 ● 基本概念 位系统下为4字节(8位十六进制数),在64位系统下为8字节(16位十六进制数) 进制表示的, 内存地址不占用内存空间 指针本身是一种数据类型, 它可以指向int, char ...

  6. Python学习笔记(十二)—Python3中pip包管理工具的安装【转】

    本文转载自:https://blog.csdn.net/sinat_14849739/article/details/79101529 版权声明:本文为博主原创文章,未经博主允许不得转载. https ...

  7. oracle学习笔记(二十) 子程序——函数与触发器

    子程序--函数 语法 之前select语句中使用的函数,都是SQL内置函数,我们可以通过自定义函数更满足我们的需要. 自定义函数的语法和存储过程差不多. create [or replace] $fu ...

  8. oracle学习笔记(二十二) REF 动态游标

    动态游标 定义语法 --声明 $cursor_name$ sys_refcursor --打开动态游标 open $cursor_name$ is 查询语句; --关闭游标 close $cursor ...

  9. Oracle学习笔记(二)——临时表

    在针对大数据量的多表级联查询或复杂事务处理的时候,引入Oracle临时表是一种不错的策略.因此,在解决实际需求时经常会遇到需要使用存储过程和临时表相互配合的情况.下面就Oracle如何创建临时表以及注 ...

随机推荐

  1. 树莓派系列教程:安装系统与配置环境,使用PuTTy与VNC图形界面远程登录

    本文所需物品清单: Raspberry Pi 3 Model B 主板.SD卡与读卡器(用于烧录系统) 资料整理来源在文尾 需要下载的资源与工具: 推荐系统-Raspbian 树莓派官方深度定制的硬件 ...

  2. [LeetCode系列] 最长回文子串问题

    给定字符串S, 找到其子串中最长的回文字符串.   反转法: 反转S为S', 找到其中的最长公共子串s, 并确认子串s在S中的下标iS与在S'中的下标iS'是否满足式: length(S) = iS ...

  3. TS流解析 二 *****

    1.TS格式介绍 TS:全称为MPEG2-TS.TS即"Transport Stream"的缩写.它是分包发送的,每一个包长为188字节(还有192和204个字节的包).包的结构为 ...

  4. emacs之配置4,颜色插件

    来自https://github.com/oneKelvinSmith/monokai-emacs/blob/master/monokai-theme.el monokai-theme.el ;;; ...

  5. 运维工具shell简介

    运维第一工具-shell编程 shell历史 Shell的作用是解释执行用户的命令,用户输入一条命令,Shell就解释执行一条,这种方式称为交互式(Interactive),Shell还有一种执行命令 ...

  6. 496. Next Greater Element I + 503. Next Greater Element II + 556. Next Greater Element III

    ▶ 给定一个数组与它的一个子列,对于数组中的一个元素,定义它右边第一个比他大的元素称为他的后继,求所给子列的后继构成的数组 ▶ 第 496 题,规定数组最后一个元素即数组最大元素的后继均为 -1 ● ...

  7. hex文件和bin文件区别

    HEX文件和BIN文件是我们经常碰到的2种文件格式.因为自己也是新手,所以一直对这两个文件懵懵懂懂,不甚了解,最近在做STM32单片机的IAP更新,其中要考虑HEX文件和BIN文件,所以需要学习下这两 ...

  8. 跟我学算法-xgboost(集成算法)基本原理推导

    1.构造损失函数的目标函数 2.对目标函数进行泰勒展开 3.把样本遍历转换成叶子节点遍历,合并正则化惩罚项 4.求wj进行求导,使得当目标函数等于0时的wj的值 5.将求解得到的wj反导入方程中,解得 ...

  9. libcurl使用心得-包括下载文件不存在处理相关(转)

    libcurl使用心得 Libcurl为一个免费开源的,客户端url传输库,支持FTP,FTPS,TFTP,HTTP,HTTPS,GOPHER,TELNET,DICT,FILE和LDAP,跨平台,支持 ...

  10. HTTP协议入门基础

    HTTP--Hyper Text Transfer Protocol,超文本传输协议,是一种建立在TCP上的无状态连接. 整个基本的工作流程是 :客户端发送一个HTTP请求,说明客户端想要访问的资源和 ...