Oracle 函数和存储过程的区别和联系 总结版
oracle存储过程与函数的区别
2017年08月15日 22:49:38 冷月葬花魂iiii 阅读数:7800更多
个人分类: oracle
定义:
存储过程(Stored Procedure )是一组为了完成特定功能的SQL 语句集,经编译后存储在数据库中。用户通过指定存储过程的名字并给出参数(如果该存储过程
带有参数)来执行它。
存储过程是数据库中的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程。
存储过程是由流控制和SQL 语句书写的过程,这个过程经编译和优化后存储在数据库服务器中,应用程序使用时只要调用即可。
在Oracle 中,若干个有联系的过程可以组合在一起构成程序包。
优 点:
1. 存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。
2.当对数据库进行复杂操作时(如对多个表进行Update、Insert、Query、Delete时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。
3.存储过程可以重复使用,可减少数据库开发人员的工作量。
4.安全性高,可设定只有某用户才具有对指定存储过程的使用权。
存储过程与函数的对比
存储过程的优缺点
优点:减少网络交互的成本。
缺点:
a、不可移植性,每种数据库的内部编程语法都不太相同,当你的系统需要兼容多种数据库时,最好不要用存储过程。
b、学习成本高,DBA一般都擅长写存储过程,但并不是每个程序员都能写好存储过程,除非你的团队有较多的开发人员熟悉写存储过程,否则后期系统维护会产生问题。
c、业务逻辑多处存在,采用存储过程后也就意味着你的系统有一些业务逻辑不是在应用程序里处理,这种架构会增加一些系统维护和调试成本。
d、存储过程和常用应用程序语言不一样,它支持的函数及语法有可能不能满足需求,有些逻辑就只能通过应用程序处理。
e、如果存储过程中有复杂运算的话,会增加一些数据库服务端的处理成本,对于集中式数据库可能会导致系统可扩展性问题。
f、为了提高性能,数据库会把存储过程代码编译成中间运行代码(类似于Java的class文件),所以更像静态语言。当存储过程引用的对像(表、视图等等)结构改变后,
存储过程需要重新编译才能生效,在24*7高并发应用场景,一般都是在线变更结构的,所以在变更的瞬间要同时编译存储过程,这可能会导致数据库瞬间压力上升引起故障
(oracle数据库就存在这样的问题)。
本质上没区别。只是函数有如:只能返回一个变量的限制。而存储过程可以返回多个。而函数是可以嵌入在sql中使用的,可以在select中调用,而存储过程不行。执行的本质都一样。
函数限制比较多,比如不能用临时表,只能用表变量.还有一些函数都不可用等等.而存储过程的限制相对就比较少
1. 一般来说,存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强。
2. 对于存储过程来说可以返回参数,而函数只能返回值或者表对象。
3. 存储过程一般是作为一个独立的部分来执行(EXEC执行),而函数可以作为查询语句的一个部分来调用(SELECT调用),由于函数可以返回一个表对象,因此它可以在查询语句中位于FROM关键字的后面。
4. 当存储过程和函数被执行的时候,SQL Manager会到procedure cache中去取相应的查询语句,如果在procedure cache里没有相应的查询语句,SQL Manager就会对存储过程和函数进行编译。
Procedure cache中保存的是执行计划 (execution plan) ,当编译好之后就执行procedure cache中的execution plan,之后SQL SERVER会根据每个execution plan的实际情况来考虑是否要在cache中保存这个plan,评判的标准一个是这个execution plan可能被使用的频率;其次是生成这个plan的代价,也就是编译的耗时。保存在cache中的plan在下次执行时就不用再编译了。
https://blog.****.net/u012102536/article/details/77203030
竹沥半夏
随笔- 12 文章- 0 评论- 8
oracle中函数和存储过程的区别和联系
oracle中函数和存储过程的区别和联系
在oracle中,函数和存储过程是经常使用到的,他们的语法中有很多相似的地方,但也有自己的特点。刚学完函数和存储过程,下面来和大家分享一下自己总结的关于函数和存储过程的区别。
一、存储过程
1.定义
存储过程是存储在数据库中提供所有用户程序调用的子程序,定义存储过程的关键字为procedure。
2.创建存储过程
create [or replace] procedure 存储过程名
[(参数1 类型,参数2 out 类型……)]
as
变量名 类型;
begin
程序代码体
end;
示例一:无参无返
create or replace procedure p1 --or replace代表创建该存储过程时,若存储名存在,则替换原存储过程,重新创建 --无参数列表时,不需要写() as begin dbms_output.put_line('hello world'); end; --执行存储过程方式1 set serveroutput on; begin p1(); end; --执行存储过程方式2 set serveroutput on; execute p1();
示例二:有参有返
create or replace procedure p2 (name in varchar2,age int,msg out varchar2) --参数列表中,声明变量类型时切记不能写大小,只写类型名即可,例如参数列表中的name变量的声明 --参数列表中,输入参数用in表示,输出参数用out表示,不写时默认为输入参数。 ------------输入参数不能携带值出去,输出参数不能携带值进来,当既想携带值进来,又想携带值出去,可以用in out as begin msg:='姓名'||name||',年龄'||age; --赋值时除了可以使用:=,还可以用into来实现 --上面子句等价于select '姓名'||name||',年龄'||age into msg from dual; end; --执行存储过程 set serveroutput on; declare msg varchar2(100); begin p2('张三',23,msg); dbms_output.put_line(msg); end;
示例三:参数列表中有in out参数
create or replace procedure p3 (msg in out varchar2) --当既想携带值进来,又想携带值出去,可以用in out as begin dbms_output.put_line(msg); --输出的为携带进来的值 msg:='我是从存储过程中携带出来的值'; end; --执行存储过程 set serveroutput on; declare msg varchar2(100):='我是从携带进去的值'; begin p3(msg); dbms_output.put_line(msg); end;
示例四:存储过程中定义参数
create or replace procedure p4 as --存储过程中定义的参数列表 name varchar(50); begin name := 'hello world'; dbms_output.put_line(name); end; ---执行存储过程 set serveroutput on; execute p4();
总结:1.创建存储过程的关键字为procedure。
2.传参列表中的参数可以用in,out,in out修饰,参数类型一定不能写大小。列表中可以有多个输入输出参数。
3.存储过程中定义的参数列表不需要用declare声明,声明参数类型时需要写大小的一定要带上大小。
4.as可以用is替换。
5.调用带输出参数的过程必须要声明变量来接收输出参数值。
6.执行存储过程有两种方式,一种是使用execute,另一种是用begin和end包住。
存储过程虽然有很多优点,但是它却不能使用return返回值。当需要使用return返回值时,我们可以使用函数。
二、存储函数
1.函数与存储过程的结构类似,但是函数必须有一个return子句,用于返回函数值。
create or replace function f1 return varchar--必须有返回值,且声明返回值类型时不需要加大小 as msg varchar(50); begin msg := 'hello world'; return msg; end; --执行函数方式1 select f1() from dual; --执行函数方式2 set serveroutput on; begin dbms_output.put_line(f1()); end;
三、存储过程与存储函数的区别和联系
相同点:1.创建语法结构相似,都可以携带多个传入参数和传出参数。
2.都是一次编译,多次执行。
不同点:1.存储过程定义关键字用procedure,函数定义用function。
2.存储过程中不能用return返回值,但函数中可以,而且函数中必须有return子句。
3.执行方式略有不同,存储过程的执行方式有两种(1.使用execute2.使用begin和end),函数除了存储过程的两种方式外,还可以当做表达式使用,例如放在select中(select f1() form dual;)。
总结:如果只有一个返回值,用存储函数,否则,一般用存储过程。
分类: oracle基础
标签: oracle, 函数, 存储过程, 函数和存储过程的区别和联系, function, procedure, return
6
0
« 上一篇:oracle系统函数(日期函数)
» 下一篇:oracle用户和权限
http://www.cnblogs.com/zlbx/p/4818007.html
woonu
业精于勤,荒于嬉;行成于思,毁于随。——韩愈
随笔-32 文章-0 评论-2
存储过程,存储函数(Oracle)
存储过程和存储函数
指存储在数据库中供所有用户程序调用的子程序叫存储过程、存储函数。
存储过程和存储函数的区别?
存储函数:可以通过return 语句返回函数值。
存储过程:不能
除此之外我们可以认为他们是完全一样的。
存储过程
1、创建存储过程
用create procedure命令简历存储过程。
语法:
create [or replace] procedure 过程名(参数列表)
as
PLSQL子程序体;
打印hello word
--打印hello world create or replace procedure sayhelloworld as --说明部分 begin dbms_output.put_line('hello world'); end; /
编译后:
2、调用存储过程方法:
1、exec 过程名
2、begin
过程名;
过程名;
end;
/
测试调用存储过程
--连接数据库 C:\WINDOWS\system32>sqlplus scott/[email protected]:1521/orcl SQL>--调用方式一 SQL> set serveroutput on SQL> exec sayhelloworld; hello world PL/SQL 过程已成功完成。 SQL> --调用方式二: SQL> begin 2 sayhelloworld(); 3 sayhelloworld(); 4 end; 5 / hello world hello world PL/SQL 过程已成功完成。
带参数的存储过程:
--给指定员工薪水涨100,并且打印涨前和涨后的薪水 create or replace procedure raiseSalary(eno in number) --in为输入参数 as --说明部分 psal emp.sal%type; begin --得到涨前的薪水 select sal into psal from emp where empno=eno; update emp set sal=sal+100 where empno=eno; --要不要commit? --为保证在同一事务中,commit由谁调用谁提交 dbms_output.put_line('涨前:'||psal||' 涨后:'||(psal+100)); end; /
测试:
存储函数
函数(function)为一命名的存储程序,可带参数,并返回一计算值。函数和过程的结构类似,但必须有一个return子句,用于返回函数值。函数说明要指定函数名、结果值的类型,以及参数类型等。
存储函数语法:
create[or replace] functiion 函数名(参数列表)
return函数值类型
as
PLSQL子程序体;
查询员工年收入
--查询某个员工的年收入 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; /
测试:
过程和函数中的in 和out
一般来讲,过程和函数的区别在于函数可以有一个返回值;而过程没有返回值。
但过程和函数都可以通过out指定一个或多个输出参数,我们可以利用out参数,在过程和函数中实现返回多个值。
什么时候用存储过程/存储函数?
原则(不是必须的):
如果只有一个返回值,用存储函数;否则,就用存储过程。
存储过程
create or replace procedure queryEmpInfo(eno in number, pname out varchar2, psal out number, pjob out varchar2) as begin select ename,sal,empjob into pname,psal,pjob from emp where empno=eno; end;
测试
使用java程序调用存储过程
/* * 存储过程 * create or replace procedure queryEmpInfo(eno in number, * pename out varchar2, * psal out number, * pjob out varchar2) */ @Test public void testProcedure() { // {call <procedure-name>[(<arg1>,<arg2>, ...)]} String sql = "{call queryEmpInfo(?,?,?,?)}"; CallableStatement call = null; Connection connection = JDBCUtils.getConnection(); try { call = connection.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 (SQLException e) { e.printStackTrace(); }finally{ JDBCUtils.release(connection, call, null); } }
使用java程序调用存储函数
/* * 存储函数 * create or replace function queryEmpIncome(eno in number) return number */ @Test public void testFunction() { // {?= call <procedure-name>[(<arg1>,<arg2>, ...)]} String sql = "{?=call queryEmpIncome(?)}"; Connection conn = null; CallableStatement call = null; try { conn = JDBCUtils.getConnection(); call = conn.prepareCall(sql); //对于out参数,赋值 call.registerOutParameter(1, OracleTypes.NUMBER); //对于in参数,赋值 call.setInt(2, 7839); //执行 call.execute(); //取出数据 double income = call.getDouble(1); System.out.println(income); } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.release(conn, call, null); } }
在out参数中使用光标
问题:查询某个部门中所有员工的所有信息
1、申明包结构
CREATE OR REPLACE PACKAGE MYPACKAGE AS type empcursor is ref cursor; --创建存储过程,输出参数为自定义类型 procedure queryEmpList(dno in number,empList out empcursor); END MYPACKAGE;
2、创建包体(实现)
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;
使用java调用带包的存储过程
public void testCursor() { // {call <procedure-name>[(<arg1>,<arg2>, ...)]} String sql = "{call MYPACKAGE.queryEmpList(?,?)}"; Connection conn = null; CallableStatement call = null; ResultSet rs = null; try { conn = JDBCUtils.getConnection(); call = conn.prepareCall(sql); //对于in参数,赋值ֵ call.setInt(1, 20); //对于out参数,赋值 call.registerOutParameter(2, OracleTypes.CURSOR); //执行 call.execute(); // 取出结果 rs = ((OracleCallableStatement)call).getCursor(2); while(rs.next()){ String name = rs.getString("ename"); double sal = rs.getDouble("sal"); System.out.println(name+"\t"+sal); } } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.release(conn, call, rs); } }
此案例光标没有关闭,原因:当resultSet关闭的时候 光标就close了
分类: 数据库
1
0
« 上一篇:【深入spring】IoC容器的实现
» 下一篇:PLSQL程序设计(Oracle)
https://www.cnblogs.com/dooor/p/5599351.html
Oracle中函数和存储过程的区别总结版
2016.07.21 14:02* 字数 865 阅读 2306评论 1喜欢 10
昨天下午和今天上午找了也看了很多资料,现在基本上已经把二者的区别理清楚,以后不要再弄混淆,也算是一种小小的进步吧,而不去想以后会怎样。
一、主要区别
**
**
1、二者最大的区别是:
- 1).函数(function)总是向调用者返回数据,并且一般只返回一个值;
- 2).存储过程(procedure)不直接返回数据,但可以改变输出参数的值,这可以近似看作能返回值,且存储过程输出参数的值个数没有限制。
从一般应用上来看,如果不需要返回值或者需要多个返回值,使用存储过程,如果只用一个返回值,就使用函数。
2、function定义中只能有DDL(如select等)语句;procedure中主要是DML语句(对数据库进行复杂操作时,如对多个表进行Update、Insert、Query、Delete时)。
如果想要使用select的结果集,则要使用游标
**
**
以下需要注意的地方是:
- 1).定义函数或者存储过程时,IN/OUT表示调用函数时,传进来或传出去的参数。如果没有说明in/out,则默认为in;
- 2).定义的函数必须要有return子句,其后紧跟着返回值得类型;
- 3).实际调用函数或存储过程时,在declare中声明的变量至少应该对应创建的函数或存储过程中的OUT参数和return参数合起来的个数;
- 4).可以建立不带参数(即没有返回的参数)、没有变量的存储过程。
**
**
- 5)执行方式略有不同,存储过程的执行方式有两种(1.使用execute2.使用begin和end),函数除了存储过程的两种方式外,还可以当做表达式使用,例如放在select中(select f1() form dual;)。
3、存储过程的命名最好以proc_打头,函数则是func_打头,变量则应该用v_打头。
Paste_Image.png
二、实际举例
**
**
1、函数
(1)创建函数
create or replace function get_salary(
dept_no number,
emp_count **out** number)
return number IS
v_sum number;
begin
...
exception
...
end get_salary
(2)调用函数
declare
v_num number;
v_sum number;
begin
...(这里应该出现函数名表示调用)
end
2、存储过程
(1)创建存储过程
create or replace procedure pro_demo(
dept_no number default 10,
sal_sum out number,
emp_count out number)
IS
begin
...
exception
...
end proc_demo;
(2)调用存储过程
调用语法:
1)、exec <过程名>;
2)、execute <过程名>;
3)、在PL/SQL语句块中直接调用。
例如:
declare
v_num number;
v_sum number(8,2);
begin
procedure pro_demo(dept_no=>1,sal_num=>900,emp_count=>10)(这里出现存储过程名表示调用,传递参数值用=>)
end;
3、本地存储过程
在PL/SQL中还可以在declare块中建立本地存储过程,而不使用关键字create,其目的是:不用将存储过程存储在数据库中,避免更改数据库时带来的麻烦,其主要的使用场景是,临时使用某个存储过程,而不是在以后要重复多次使用。
例子:
declare
v_num number;
v_sum number(8,2);
procedure proc_demo(
dept_no number default 10,
sal_sum out number,
emp_count out number)
IS
begin
...(这里不用出现存储过程名)
exception
...
end proc_demo;
**
**
这里再次复习一下DDL(data defined language),DML(data manipulation language ),DCL(data control language)的区别:
-
1).DDL的操作对象(表)
Create语句:可以创建数据库和数据库的一些对象。
Drop语句:可以删除数据表、索引、触发程序、条件约束以及数据表的权限等。
Alter语句:修改数据表定义及属性。 -
2).DML操作的对象是记录(即数据)
最常见的是增(insert)、删(delete)、改(update)、查(select) -
3).DCL操作的对象是数据库用户的权限
Grant语句:允许对象的创建者给某用户或某组或所有用户(PUBLIC)某些特定的权限。
Revoke语句:可以废除某用户或某组或所有用户访问权限
如果写的对你有一点点帮助,可以手动关注一下下,多谢(*¯︶¯*)
赞赏支持
© 著作权归作者所有
写了 106083 字,被 623 人关注,获得了 527 个喜欢
愿我长命百岁,yu你终老
登录 后发表评论
1条评论 只看作者
2楼 · 2017.03.07 19:38
收藏了,谢谢分享
https://www.jianshu.com/p/5a90ccd9b643
oracle之存储过程(procedure)与函数(function)
2017年09月21日 13:16:08 没腿的鸟 阅读数:382更多
个人分类: Oracle
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.****.net/qq30211478/article/details/78050830
(一)存储过程(procedure)
对于PLSql程序的使用,如果每次使用都要进行编写,会非常的麻烦,这时可以采用过程和函数来命名PLSQL程序,被编译后存储到数据库中,以备后续使用。
过程和函数统称为PL/SQL子程序,他们是被命名的PL/SQL块,均存储在数据库中,并通过输入、输出参数或输入/输出参数与其调用者交换信息。过程和函数的唯一区别是函数总向调用者返回数据,而过程则不返回数据。
在编译存储过程报错时,可以使用show error命令查看具体错误原因。
(二)存储过程格式
create or replace procedure 存储过程名( para1 varchar2, para2 out varchar2, para3 in out varchar2 ) as|is //is与as一样的作用 v_name varchar2(20); begin v_name :='zhangsf'; para3 := v_name; dbms_output.put_line('para3:'||para3); end;
上面就是一个最简单的存储过程。一个存储过程大体分为这么几个部分:
1、创建语句:create or replace procedure 存储过程名
如果没有or replace语句,则仅仅是新建一个存储过程。如果系统存在该存储过程,则会报错。Create or replace procedure 如果系统中没有此存储过程就新建一个,如果系统中有此存储过程则把原来删除掉,重新创建一个存储过程。
2、存储过程名定义:包括存储过程名和参数列表。
参数名和参数类型。参数名不能重复, 参数传递方式:IN, OUT, IN OUT
IN 表示输入参数,按值传递方式。
OUT 表示输出参数,可以理解为按引用传递方式。可以作为存储过程的输出结果,供外部调用者使用。
IN OUT 即可作输入参数,也可作输出参数。
参数的数据类型只需要指明类型名即可,不需要指定宽度。
参数的宽度由外部调用者决定。
过程可以有参数,也可以没有参数
3、变量声明块:紧跟着的as (is )关键字,可以理解为pl/sql的declare关键字,用于声明变量。
变量声明块用于声明该存储过程需要用到的变量,它的作用域为该存储过程。另外这里声明的变量必须指定宽度。遵循PL/SQL的变量声明规范。
4、过程语句块:从begin 关键字开始为过程的语句块。存储过程的具体逻辑在这里来实现。
5、异常处理块:关键字为exception ,为处理语句产生的异常。该部分为可选
6、结束块:由end关键字结果。
7、 一般,只有在确认function_name函数是新函数或是要更新的函数时,才使用OR REPALCE关键字,否则容易删除有用的函数。
8、 IN,OUT,IN OUT是形参的模式。若省略,则为IN模式。IN模式的形参只能将实参传递给形参,进入函数内部,但只能读不能写,函数返回时实参的值不变。OUT模式的形参会忽略调用时的实参值(或说该形参的初始值总是NULL),但在函数内部可以被读或写,函数返回时形参的值会赋予给实参。IN OUT具有前两种模式的特性,即调用时,实参的值总是传递给形参,结束时,形参的值传递给实参。调用时,对于IN模式的实参可以是常量或变量,但对于OUT和IN OUT模式的实参必须是变量。
(三)执行存储过程、函数
exec 存储过程名(函数);
或者
begin
存储过程名;
end;
(四)函数(与存储过程类似)
CREATE [OR REPLACE] FUNCTION function_name
(arg1 [ { IN | OUT | IN OUT }] type1 [DEFAULT value1],
[arg2 [ { IN | OUT | IN OUT }] type2 [DEFAULT value1]],
......
[argn [ { IN | OUT | IN OUT }] typen [DEFAULT valuen]])
[ AUTHID DEFINER | CURRENT_USER ]
RETURN return_type
IS | AS
<类型.变量的声明部分>
BEGIN
执行部分
RETURN expression
EXCEPTION
异常处理部分
END;
(五)实例
create or replace procedure p
is
cursor c
is
select * from emp2 for update;
begin
for v_temp in c loop
if (v_temp.deptno = 10) then
update emp2 set sal = sal + 10 where current of c;
elsif (v_temp.deptno = 20) then
update emp2 set sal = sal + 20 where current of c;
else
update emp2 set sal = sal + 50 where current of c;
end if;
end loop;
commit;
end;
--执行
exec p;
或
begin;
p;
end;
--带参数的存储过程
create or replace procedure p
(v_a in number, v_b number, v_ret out number, v_temp in out number)
is
begin
if (v_a > v_b) then
v_ret := v_a;
else
v_ret := v_b;
end if;
v_temp := v_temp + 1;
end;
--实验
declare
v_a number := 3;
v_b number := 4;
v_ret number; //用来保存函数的输出结果,供调用者使用
v_temp number := 5;
begin
p(v_a, v_b, v_ret, v_temp); //直接调用函数并出入参数
dbms_output.put_line(v_ret);
dbms_output.put_line(v_temp);
end;
-------------------
--函数
create or replace function sal_tax
(v_sal number)
return number
is
begin
if (v_sal < 2000) then
return 0.10;
elsif (v_sal < 2750) then
return 0.15;
else
return 0.20;
end if;
end;
--查询oracle中的存储过程:
方法一:
select * from user_procedures;
方法二:
select object_name,object_type,procedure_name from dba_procedures where object_type='PROCEDURE' and owner='SCOTT';
select name from user_source where type='PROCEDURE';
或者:
select object_name from user_procedures;
或者:
select object_name from user_objects where object_type='PROCEDURE' ;
②找到你所要查询的存储过程名字后,执行下面操作,可以看到存错过程内容:
select text from user_source where name ='xxxx';--(xxxx代表所要查询的存储过程名字)
------------------------------------------------
如果是函数,类似的方法,只需要把PROCEDURE,换成FUNCTION即可
删除存储过程和函数
drop procedure 存储过程名;
drop function 函数名;
https://blog.****.net/qq30211478/article/details/78050830