Oracle存储过程和存储函数创建方法(详解)

select * from emp;

/*
   存储过程  是一段封装的代码块 编译好放在服务器
             好处: 支持多处调用 提升开发效率
                   调用直接运行 提升运行效率
   创建存储过程 create [or replace] procedure 过程名(参数名 in|out
参数数据类型 )
                as|is
                  -声明部门
                begin
                   -处理逻辑代码
                end;
   存储过程的调用
       在begin 和 end之间 过程名传参调用
*/
–使用存储过程给某个员工工资增加100块钱 输出涨工资前后的数据
create or replace  procedure add_sal(eno in number)
as
   v_sal number ;
begin
   –输出原始工资
   select sal into v_sal from emp where empno=eno;
   dbms_output.put_line(‘原始工资===’||v_sal);
   –涨工资
   update emp set sal=sal+100 where empno=eno;
   commit;

—————–存储过程————————

 

–定义

 

create[or replace] procedure 存储过程名称(参数名 [in]/out 数据类型)
is/as begin

 

–逻辑表达式

   –输出修改后工资
   select sal into v_sal from emp where empno=eno;
   dbms_output.put_line(‘修改后工资===’||v_sal);
end;

end [存储过程名称];

–过程调用
declare
begin
   add_sal(7369);
end;
—–使用存储过程得到统计后的某个员工年薪
create or replace  procedure count_sal(eno number,year_sal out
number)
as
begin
   select sal*12+nvl(comm,0) into year_sal  from emp where empno =
eno;
end;

–定义存储过程计算年薪,并答应输出

–调用过程统计年薪
declare
  v_year_sal number;
begin
   count_sal(7369,v_year_sal);
   dbms_output.put_line(‘年薪==’||v_year_sal);
end;
—-使用存储过程得到某个部门下的所有员工信息
/*
   cursor 名 is select * from  表
   系统引用类型游标   声明时候不需要指定结果集 
在open打开游标时候指定结果集
   emp_cursor sys_refcursor;  —
   open   emp_cursor for select 结果集
*/
create or replace  procedure dept_emp(dno number,dept_all_emp out
sys_refcursor )
as
begin
     –给当前的系统引用游标装入数据
     open dept_all_emp for select * from emp where deptno=dno;
end;
–调用存储过程 遍历10号部门下的员工信息
declare
    all_emp sys_refcursor ; –声明系统引用游标 传参使用
    emp_row emp%rowtype;–记录类型接收游标的提取
begin
   dept_emp(10,all_emp);
   –提取游标
   loop
      –先提取后判断
      fetch all_emp into emp_row;
      exit when  all_emp%notfound;
     
dbms_output.put_line(‘eno===’||emp_row.empno||’ename==’||emp_row.ename);
   end loop;
   close all_emp;

create or replace procedure proc_salyears(v_no in number) is
sal_years number(9,2); begin

end;

/*
存储函数  是一段封装的代码块 编译好放在服务器
             好处: 支持多处调用 提升开发效率
                   调用直接运行 提升运行效率
   创建函数过程 create [or replace] function 函数名(参数名 in|out
参数数据类型 ) return 数据类型
                as|is
                  -声明部门
                begin
                   -处理逻辑代码
                   return 变量
                end;
   存储函数的调用
       在begin 和 end之间 函数名传参调用 必须有变量接收函数的返回值
*/
–使用存储函数统计年薪
create or replace function fun_count_sal(eno number) return number
as
   v_sal number;
begin
   select sal*12+nvl(comm,0) into v_sal from emp where empno=eno;
   return v_sal;
end;
–函数的调用
declare
   v_sal number;
begin
  v_sal := fun_count_sal(7369);
  dbms_output.put_line(v_sal);
end;
———out输出参数的函数获得年薪
create or replace function fun_emp_sal(eno number,emp_sal out number)
return number
as
 
begin
   select sal*12+nvl(comm,0) into emp_sal from emp where empno=eno;
   return emp_sal;

–计算年薪

end;

declare
   v_sal number;
   emp_year_sal number;
begin
  v_sal := fun_emp_sal(7369,emp_year_sal);
  dbms_output.put_line(v_sal);     –0
  dbms_output.put_line(emp_year_sal);–10800
end;
/*
   存储函数和过程的对比
       1.创建的关键字不一致  procedure function
       2.函数的创建 必须制定函数的返回数据类型
       3.函数在begin end直接必须返回变量
       4.函数的调用必须有变量接收返回值
       5.函数可以用在select 语句中
   使用场景  开发规范
       java调用过程  过程处理业务逻辑 ,如果在逻辑处理中
       用到某些功能性的封装 可以调用函数
       90%通用  函数同样可以调用过程  不是强制限制  
*/
select emp.*,fun_count_sal(empno) from emp;
/*
   触发器 一个监视器 对表中数据的操作监视
          insert  update  delete
          如果对表中数据的操作满足了触发器的执行条件
          触发器会自动执行
    创建语法  create or replace trigger 触发器名
              before|after  –执行时机
              insert|update|delete
              on 表
              declare
              begin
               
              end;
    行级触发器 针对每一行记录监视  for each row
                                  insert            update        
delete
          :new  操作之后的记录  将要插入的记录   修改后的记录    nul
          :old  操作之前的记录     null           原始记录       
原始记录
*/
—插入数据之后 输出欢迎语句
create or replace trigger insert_tri
after
insert
on dept
declare
begin
   –输出欢迎语句
   dbms_output.put_line(‘欢迎加入部门’);
end;
————–插入数据测试
insert into dept values(3,’test1′,’bj’);
commit;
—-使用触发器监视部门表 插入数据不能在休息日

/*
   数据库封装好的错误提示  raise_application_error(v1,v2)
                          v1是错误代码 -20000 -20999 v2是错误提示语
*/
create or replace trigger no_work_day
before
insert
on dept
declare
   v_day varchar(10);
begin
    –提取当前的星期 (saturday,sunday)
    select to_char(sysdate,’day’) into v_day from dual;
    –判断当前是否是休息日
    if trim(v_day) in (‘saturday’,’sunday’) then
      –不允许插入
      raise_application_error(-20001,’不能在休息日插入数据’);
    end if;
end;
select to_char(sysdate,’day’)  from dual;
—-再来一个实际应用 触发器限制表中数据操作 不能降低工资
create or replace trigger can_not_low
before
update
on emp
for each row   –行级触发器
declare
 
begin
  
    –判断修改后的工资 <小于原始的工资 不允许修改
     if :new.sal < :old.sal then
      raise_application_error(-20001,’不能降低工资’);
     end if;
end;
–修改员工表工资 测试
update emp set sal=sal-1 where empno=7369;
commit;

create table person(
   pid number(9),
   pname varchar(10),
   phone varchar(11)
)
insert into person(pname,phone) values(‘zs’,’123456′);
commit;

/*
   触发器实现id 自增长
  
*/
create or replace trigger auto_incr_id
before
insert
on person
for each row   –行级触发器
declare
 
begin
   –给id赋值 id有要求 必须是自增长的数值
   select seq_class.nextval into :new.pid from dual;
   
end;

 


//JDBC调用

public class TestJdbc {

String driverClass = “oracle.jdbc.driver.OracleDriver”;
String url =”jdbc:oracle:thin:@192.168.17.128:1521:orcl”;
String user= “itcast_03”;
String password = “itcast_03”;
/*
*测试jdbc连接数据库
*
* */
@Test
public void querEmp(){
try{
//加载驱动
Class.forName(driverClass);
//获取链接
Connection con = DriverManager.getConnection(url, user,password);
//获取预编译的statement
PreparedStatement pst= con.prepareStatement(“select * from emp”);
//执行查询
ResultSet rs = pst.executeQuery();
//处理结果
while(rs.next()){
System.out.println(rs.getInt(1)+”员工姓名”+rs.getString(“ename”));
}
rs.close();
con.close();
//关闭连接
}catch(Exception e){
e.printStackTrace();
}

}
/*存储过程的调用
* {call <procedure-name>[(<arg1>,<arg2>, …)]}
add_sal(eno number,addsal number)
* */
@Test
public void callAddSal(){
try{
//加载驱动
Class.forName(driverClass);
//获取链接
Connection con = DriverManager.getConnection(url, user,password);
//获取预编译的statement
CallableStatement pst= con.prepareCall(“{call add_sal(?,?)}”);
pst.setInt(1, 7499);
pst.setInt(2, 1000);
//执行查询
pst.execute();
con.close();
//关闭连接
}catch(Exception e){
e.printStackTrace();
}

}

/*存储过程的调用
* {call <procedure-name>[(<arg1>,<arg2>, …)]}
count_yearsal(eno number,total_year_sal out number)
* */
@Test
public void callCountSal(){
try{
//加载驱动
Class.forName(driverClass);
//获取链接
Connection con = DriverManager.getConnection(url, user,password);
//获取预编译的statement
CallableStatement pst= con.prepareCall(“{call count_yearsal(?,?)}”);
pst.setInt(1, 7499);
//注册输出参数
pst.registerOutParameter(2, OracleTypes.NUMBER);
//执行查询
pst.execute();
int total = pst.getInt(2);
System.out.println(total);
con.close();
//关闭连接
}catch(Exception e){
e.printStackTrace();
}

}
/*
* pro_dept_emp(dno number,dept_emp out sys_refcursor)
* */
@Test
public void callProEmp(){
try{
//加载驱动
Class.forName(driverClass);
//获取链接
Connection con = DriverManager.getConnection(url, user,password);
//获取预编译的statement
CallableStatement pst= con.prepareCall(“{call pro_dept_emp(?,?)}”);
pst.setInt(1, 10);
//注册输出参数
pst.registerOutParameter(2, OracleTypes.CURSOR);
//执行查询
pst.execute();
OracleCallableStatement ocs = (OracleCallableStatement)pst;
ResultSet rs = ocs.getCursor(2);
while(rs.next()){
System.out.println(rs.getInt(1)+”员工姓名”+rs.getString(“ename”));
}
rs.close();
ocs.close();
pst.close();
con.close();
//关闭连接
}catch(Exception e){
e.printStackTrace();
}

}
}

 ============================

hibernate5调用存储过程

@Test
public void fun2(){
    Session session = JDBCUtils.openSession();
    ProcedureCall pc = session.createStoredProcedureCall("proc_emp_yearsal");//存储过程的名称
    pc.registerParameter("v_no", Long.class, ParameterMode.IN).bindValue(7788l);
    //参数1:对应存储过程中的变量名1,参数2:类型,参数3:是in还是out,参数4:手动设置了一个查询参数
    pc.registerParameter("v_yearSal", Long.class, ParameterMode.OUT);
    String string = pc.getOutputs().getOutputParameterValue("v_yearSal").toString();
    System.out.println(string);
}

select sal*12+nvl(comm,0) into sal_years from emp where empno=v_no;

–输出

dbms_output.put_line(sal_years); end;

–调用存储过程

方式1:

call proc_salyears(7788);

方式2:

begin proc_salyears(7369); end;

–out参数的存储过程