数据库小技能:存储过程(stored procedure)

简介: 过程(procedure)又叫存储过程(stored procedure),是一个有名称的PL/SQL程序块 。过程相当于java中的方法, 它注重的是实现某种业务功能 。函数(function)也相当于java中的方法,它 注重计算并且总是有返回结果 。过程和函数都是能够永久存储在数据库中的程序代码块,应用时通过调用执行 。

引言

过程(procedure)又叫存储过程(stored procedure),是一个有名称的PL/SQL程序块 。

过程相当于java中的方法, 它注重的是实现某种业务功能 。
函数(function)也相当于java中的方法,它 注重计算并且总是有返回结果 。

过程和函数都是能够永久存储在数据库中的程序代码块,应用时通过调用执行 。

I 过程的基本结构

create [or replace ] procedure 过程名称(形参名称  形参类型,形参名称  形参类型······) 
is | as  
定义变量 
begin 
过程体 
exception 
异常 
end;

1.1 含有输入参数的过程

输入参数 用in 标识 可省略

        --过程
        create or replace  procedure mypro(p_id in number,p_sal in number)
        is
               v_count number(3);
               v_no number(3);
        begin
               select count(*) into v_count from emp where empno = p_id;
               if v_count > 0 then
              update emp set  sal = sal+p_sal where empno=p_id;
              v_no := sql%rowcount;
              commit;
              dbms_output.put_line(v_no||'rows updated');
               else
              dbms_output.put_line('记录不存在');
               end if;
        end;

1.2 无参的过程

    --无参的过程
        create or replace  procedure mypro_noparam
        is
               v_count number(3);
              
        begin
               select count(*) into v_count from emp where empno = 7788;
              
               dbms_output.put_line(v_count||' 条记录');
               
        end;
 

1.3 有输出参数的过程

输出参数用 out 标识

        --含有输出参数的过程
        create or replace procedure mypro(p_id in number, p_sal out  number)
        is
        begin
               select sal into p_sal from emp where empno=p_id;
        end;

II 过程的调用

2.1 通过匿名块调用

  1. 输入参数
        --通过匿名块调用过程
        begin
            mypro(1234,100);   
        end;
  1. 输出参数过程
        declare
               v_sal number(10);
        begin
             mypro(7788,v_sal);
             dbms_output.put_line(v_sal);
        end;
  1. 无参的过程
begin 
    mypro_noparam; 
end; 

2.2 命令行调用

#1. 调用输入参数 
SQL> exec mypro(7788,3000); 
# 2.输出参数 
SQL> var v_sal number;  # 注册变量 
SQL> exec mypro(7788,:v_sal); #:变量名称 使用变量接收输出 
# 3.调用无参 
SQL> exec mypro; 

————————————————
版权声明:本文为CSDN博主「iOS逆向」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

示例:

  1. 写一个过程来封装emp表中的数据
/*写一个过程封装emp表中的数据*/
create or replace procedure  my_pro
is
      type v_table is table of emp%rowtype index by binary_integer;
      --定义表类型的变量
      v_data v_table;
      --定义游标类型
      type table_cursor is ref cursor return emp%rowtype;
      --定义游标变量
      v_myCursor table_cursor;
      v_index binary_integer:=0;
begin
      --开启游标
      open v_myCursor for select * from emp;
      
      --获取数据
      loop 
           
          fetch v_myCursor into v_data(v_index);
          --打印数据
          exit when v_myCursor%notfound;
          dbms_output.put_line(v_data(v_index).deptno||'____________'||v_data(v_index).empno);
          --下标的自增
          v_index :=v_index+1;
      end loop;
      close v_myCursor;
      
end;
 
 
--调用过程
begin
      my_pro;
end;

  1. 写一个过程:输入员工编号,通过游标获取,输出该员工对应下属的信息 。
/*写一个过程输入员工编号,通过游标获取输出该员工对应下属的信息*/
create or replace procedure  my_pro(p_id in number)
is
      type v_table is table of emp%rowtype index by binary_integer;
      --定义表类型的变量
      v_data v_table;
      --定义游标类型
      type table_cursor is ref cursor return emp%rowtype;
      --定义游标变量
      v_myCursor table_cursor;
      v_index binary_integer:=0;
begin
      --开启游标
      open v_myCursor for select * from emp where mgr=p_id;
      
      --获取数据
      loop 
           
          fetch v_myCursor into v_data(v_index);
          --打印数据
          exit when v_myCursor%notfound;
          dbms_output.put_line(v_data(v_index).deptno||'____________'||v_data(v_index).empno);
          --下标的自增
          v_index :=v_index+1;
      end loop;
      close v_myCursor;
      
end;
 
 
--调用过程
begin
      my_pro(&no);
end;

  1. 计算100-200的素数
/*计算100-200的素数*/
declare
  
begin
  execute immediate ('create or replace procedure myPro 
          is
                    v_flag boolean ;
          begin
                   for i in 100..200 loop
                                        
                       v_flag:=true;--默认为是素数
                       --增加除数
                       for j in 2..i/2 loop
                          
                              if i mod j =0 then
                                    v_flag:=false;--标记为不是素数
                                   exit;
                                                                                             
                              end if;
                    
                       end loop;
                            --打印素数
                            if v_flag then
                               dbms_output.put_line(i);
                            end if;     
                   end loop;
          end;
  ');
   
end;
 
 
begin
 myPro;    
end;

2.3 通过java调用过程

package jdbcPlSQL;
 
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
 
import oracle.jdbc.driver.OracleTypes;
import util.CoonectionUtil;
 
public class TestPLSQL {
    public static void main(String[] args) {
        Connection conn=null;
        CallableStatement cstmt=null;
        //调用无参的过程
        //String sql="{call my_Porcedure()}";
        //调用有参的过程
        //String sql="{call mypro(?,?)}";
        //调用有输出参数的过程
        String sql="{call myPorcedure(?,?)}";
        try {
            conn=CoonectionUtil.getConn();
            cstmt=conn.prepareCall(sql);
            cstmt.setInt(1, 7369);
            //住入输出参数oracle.jdbc.driver.OracleTypes//Types
            
            cstmt.registerOutParameter(2, Types.INTEGER);
            cstmt.execute();
            //获取输出参数的值
            System.out.println(cstmt.getInt(2));
            
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

III 自定义函数

/*创建函数*/
create or replace function my_fun(p_deptno number)
return number
is
       v_num number(10);
begin
       select count(*) into v_num from emp where deptno=p_deptno;
       return v_num;
end;
 
declare
       v_num number(10);
begin
         v_num :=my_fun(20);
       dbms_output.put_line(v_num);
end;
 
/*含有输出参数的函数*/
create or replace function my_fun(p_id number,p_ename out varchar2)
return number
is
       v_deptno number(10);
       
begin
       select deptno,ename into v_deptno,p_ename from emp where empno=p_id;
       return v_deptno;
end;
 
--调用含有输出参数的函数
declare
       v_deptno number(10);
       v_ename varchar2(30);
begin
         v_deptno := my_fun(7788,v_ename);
       dbms_output.put_line(v_deptno||'*************'||v_ename);
end;

IV 异常

系统异常分为预定义异常和非预定义异常。

  • 预定义异常:是由数据库定义好,含有异常编码,异常名称,异常信息;
大概有20种,例如 too_many_rouws; no_data_found; zero_divide
  • 非预定义异常:异常编码,异常信息,但没有异常名称。

4.1非预定义异常

代码示例

/*非预定义的异常*/
declare
  --定义异常名称
  e_noFather exception;
  --绑定异常名称与异常编码
  pragma exception_init(e_noFather,-02291);
begin
  insert into emp(empno,deptno) values(1111,99);
  commit;
--处理异常
exception
  when e_noFather then
  dbms_output.put_line('该部门不存在');
end;

4.2 自定义异常

/*自定义异常*/
declare
  v_ename_search varchar2(20);
  v_empno number(10):=&no;
  v_ename varchar2(20):=upper('&pwd');
  --自定义异常
  
   --定义异常名称
  e_pwdErr exception;
  --绑定异常名称与异常编码
  pragma exception_init(e_pwdErr,-20291);
begin
    select ename into  v_ename_search from emp where empno=v_empno;
    --产生异常
    if  v_ename_search=v_ename then
        dbms_output.put_line('登陆成功');
     else
        --raise e_pwdErr;
        --抛异常
          dbms_standard.raise_application_error(-20291,'密码不正确',false);
    end if;
exception
     when no_data_found then
          dbms_output.put_line('该用户不存在');
     --when e_pwdErr then
        --dbms_output.put_line('密码不正确');
end;
 
 
/*自定义异常根据员工号计算谁工资低于3000,并计算他的入职时间*/
create or replace procedure my_pro(v_empno number)
is
 
  --员工的的sal
 v_sal number(20);
  --员工的入职时间
  v_time number(10);
  --自定义异常
  
   --定义异常名称
  e_lowsal exception;
  --绑定异常名称与异常编码
  pragma exception_init(e_lowsal,-20291);
begin
    select sal into  v_sal from emp where empno=v_empno;
    --产生异常
    if  v_sal<3000 then
        select (sysdate-hiredate) into  v_time from emp where empno=v_empno;
        raise e_lowsal;  --产生异常
    end if;
     
exception
    --员工不存在的异常
     when no_data_found then
          dbms_output.put_line('该员工不存在');
     when e_lowsal then
        dbms_output.put_line(v_empno||'白吃了'||v_time||'天这么长的时间的饭,还只拿这样的工资'||v_sal);
end;
 

V 包

包用于管理过程和函数,包分为包头和包体。

  • 包一定要有包头,包头负责声明函数、过程、变量和常量。包头可单独定义,单独定义的包头只能含有常量。
  • 包体具体来实现包头所声明定义的函数和过程,包体封装实现。

5.1 代码示例

/*声明包头*/
 
--声明包头
create or replace package package_emp 
is
 
       --声明游标类型
       type  my_cursor is ref cursor return emp%rowtype;
       --定义过程
       procedure my_pro (p_cursor out my_cursor );
      
       --定义函数
       function my_fun return number;
end;
 
/*声明包体*/
create or replace package body package_emp
is
       --实现过程
        procedure my_pro (p_cursor out my_cursor )
        is
        begin
        
                  open p_cursor for select * from emp;
        end;
        --函数的实现
        function my_fun 
        return number
        is
               v_num number(10);
        begin
              select sum(sal) into  v_num from emp;  
              return v_num;   
        end;
 
end;
 
/*调用包中的过程与方法*/
declare
       --不要return
      type  my_cursor is ref cursor ;  
      --定义游标类型的变量
      v_cursor my_cursor;
      --总工资
      v_num number(10);
      --记录类型的变量
      v_recored emp%rowtype;
       
begin
      package_emp.my_pro(v_cursor);
      --打印数据
      loop
                --游标已在包体中开启
            fetch v_cursor into v_recored;
            dbms_output.put_line(v_recored.ename);
            exit when v_cursor%notfound;
      end loop;
      close v_cursor;
       --获取函数的返回值
      v_num:=package_emp.my_fun;
      dbms_output.put_line(v_num);
     
end;

5.2 jdbc调用含有包的过程体

代码示例

package package_JDBC;
 
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
 
import oracle.jdbc.driver.OracleTypes;
 
import testlife.ConnectionUtil;
/**
 * 
 * @author zhang_kn
 *    调用包中的过程
 */
public class Package_Procedure {
    public static void main(String[] args){
        //获取连接
        Connection conn=ConnectionUtil.getConn();
        //System.out.println(conn);
        //调用在包中的过程,该过程含有输出参数
        String sql="{call package_emp.my_pro(?)}";
        CallableStatement cstmt=null;
        ResultSet rs=null;
        try {
            cstmt=conn.prepareCall(sql);
            //注入参数
            cstmt.registerOutParameter(1,OracleTypes.CURSOR);
            cstmt.execute();
            //获取输出参数
            rs=(ResultSet) cstmt.getObject(1);
        
            while(rs.next()){
                //获取数据
                System.out.println(rs.getInt(1));
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                ConnectionUtil.close(conn,cstmt,rs);
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

目录
相关文章
|
4月前
|
存储 SQL 关系型数据库
MySql数据库---存储过程
MySql数据库---存储过程
69 5
|
6月前
|
人工智能 小程序 关系型数据库
【MySQL】黑悟空都掌握的技能,数据库隔离级别全攻略
本文以热门游戏《黑神话:悟空》为契机,深入浅出地解析了数据库事务的四种隔离级别:读未提交、读已提交、可重复读和串行化。通过具体示例,展示了不同隔离级别下的事务行为差异及可能遇到的问题,如脏读、不可重复读和幻读等。此外,还介绍了在MySQL中设置隔离级别的方法,包括全局和会话级别的调整,并通过实操演示了各隔离级别下的具体效果。本文旨在帮助开发者更好地理解和运用事务隔离级别,以提升数据库应用的一致性和性能。
164 2
【MySQL】黑悟空都掌握的技能,数据库隔离级别全攻略
|
6月前
|
存储 SQL 安全
【数据库高手的秘密武器:深度解析SQL视图与存储过程的魅力——封装复杂逻辑,实现代码高复用性的终极指南】
【8月更文挑战第31天】本文通过具体代码示例介绍 SQL 视图与存储过程的创建及应用优势。视图作为虚拟表,可简化复杂查询并提升代码可维护性;存储过程则预编译 SQL 语句,支持复杂逻辑与事务处理,增强代码复用性和安全性。通过创建视图 `high_earners` 和存储过程 `get_employee_details` 及 `update_salary` 的实例,展示了二者在实际项目中的强大功能。
61 1
|
6月前
|
存储 SQL JSON
【Azure Logic App】微软云逻辑应用连接到数据库,执行存储过程并转换执行结果为JSON数据
【Azure Logic App】微软云逻辑应用连接到数据库,执行存储过程并转换执行结果为JSON数据
【Azure Logic App】微软云逻辑应用连接到数据库,执行存储过程并转换执行结果为JSON数据
|
6月前
|
存储 SQL 数据库
触发器的设计、掌握存储过程的基本概念和创建、执行、删除方法。掌握数据库备份的方法和数据库恢复的方法。
这篇文章介绍了数据库中触发器的设计概念,包括创建、修改、删除触发器的方法,并通过实验内容教授如何使用SQL命令创建DML触发器以及如何利用触发器实现数据的完整性和自动化处理。
触发器的设计、掌握存储过程的基本概念和创建、执行、删除方法。掌握数据库备份的方法和数据库恢复的方法。
|
6月前
|
JSON 数据格式 Java
化繁为简的魔法:Struts 2 与 JSON 联手打造超流畅数据交换体验,让应用飞起来!
【8月更文挑战第31天】在现代 Web 开发中,JSON 成为数据交换的主流格式,以其轻量、易读和易解析的特点受到青睐。Struts 2 内置对 JSON 的支持,结合 Jackson 库可便捷实现数据传输。本文通过具体示例展示了如何在 Struts 2 中进行 JSON 数据的序列化与反序列化,并结合 AJAX 技术提升 Web 应用的响应速度和用户体验。
170 0
|
6月前
|
存储 SQL 数据库
|
6月前
|
SQL 网络协议 数据库连接
"解锁数据连接新技能:Python携手SqlServer,轻松驾驭企业级数据库挑战!"
【8月更文挑战第21天】本文介绍如何在Python中连接SqlServer数据库。首先,需安装`pyodbc`库:`pip install pyodbc`。接着配置数据库详情如服务器地址、端口等。示例代码展示如何建立连接、执行查询及处理结果。务必确认TCP/IP已启用并使用合适ODBC驱动。了解这些步骤可助您更好地利用Python进行数据管理。
134 0
|
8月前
|
存储 SQL 关系型数据库
MySQL数据库进阶第四篇(视图/存储过程/触发器)
MySQL数据库进阶第四篇(视图/存储过程/触发器)
|
8月前
|
存储 关系型数据库 MySQL
MySQL数据库——存储过程-条件处理程序(通过SQLSTATE指定具体的状态码,通过SQLSTATE的代码简写方式 NOT FOUND)
MySQL数据库——存储过程-条件处理程序(通过SQLSTATE指定具体的状态码,通过SQLSTATE的代码简写方式 NOT FOUND)
64 0
MySQL数据库——存储过程-条件处理程序(通过SQLSTATE指定具体的状态码,通过SQLSTATE的代码简写方式 NOT FOUND)

热门文章

最新文章