zoukankan      html  css  js  c++  java
  • Oracle笔记4-pl/sql-分支/循环/游标/异常/存储/调用/触发器

    一.pl/sql(Procedure Language/SQL)编程语言
    1.概念
    PL/SQL是Oracle数据库对SQL语句的扩展。在普通SQL语句的使用上增加了编程语言的特点,所以PL/SQL把数据操作和查询语句组织在PL/SQL代码的过程性单元中,通过逻辑判断、循环等操作实现复杂的功能或者计算。PL/SQL 只有 Oracle 数据库有。 MySQL 目前不支持 PL/SQL 的。

    2.变量和常量
    声明普通变量:
         v_name varchar2(30) := 'tom';  (:=为赋值符号;=为比较符号,相当于java中的==);
    声明引用型变量:
         v_sal emp.sal%type := 100;    声明的v_sal变量与emp表中sal字段的类型一致;
    声明记录型变量:
         v_row emp%rowtype; 记录型变量相当于java中的resultset,用来存储整张表中的数据;
    声明常量:
         v_gender constant number(1) number(1) := 1;   

    3.分支语句
    语法一:if ---then---end if;
    语法二:if ---then---else---end if;
    语法三:if ---then---elsif---then----else----end if;
    举例:
    --年龄小于18,显示未成年人,18-60,显示成年人,60以上显示老年人
    declare
         v_age number(8) :=#
    begin
         if v_age < 18 then
             dbms_output.put_line('未成年人');
         elsif v_age >= 18 and v_age <= 60 then
             dbms_output.put_line('成年人');
         else
             dbms_output.put_line('老年人');
         end if;
    end;


    4.循环语句
    语法一:loop---exit when----end loop;
    举例:
    --输出1--100的数
    declare
      v_num number(8) := 1;
    begin
      loop
       exit when v_num > 100;
       dbms_output.put_line(v_num);
       v_num := v_num + 1;
      end loop;
    end;

    语法二:while---loop----end loop;
    declare
      v_num number(8) := 1;
    begin
      while v_num <= 100 loop
       dbms_output.put_line(v_num);
       v_num := v_num + 1;
      end loop;
    end;

    语法三:for---in 起始值..终止值---loop---end loop;
    declare
      v_num number(8) := 1;
    begin
      for v_num in 1 .. 100 loop
       dbms_output.put_line(v_num);
      end loop;
    end;

    5.游标(cursor)
    作用:用来接收多条数据结果,相当于java中的ResultSet
    语法:cursor 游标名称 is sql 查询语句;
    使用:
         open 游标名称
         loop
             fetch 游标名称 into 记录型变理
             exit when 游标名称%notfound;
                 逻辑处理
         end loop;
         close 游标名称;
    举例:
    --打印emp表的所有信息
    DECLARE
      CURSOR c_emp IS SELECT * FROM emp;
      v_row emp%ROWTYPE;
    BEGIN
      OPEN c_emp;
      LOOP
        FETCH c_emp INTO v_row;
              EXIT WHEN c_emp%NOTFOUND;
              dbms_output.put_line(v_row.ename||'--'||v_row.job);
       END LOOP;
       CLOSE c_emp;
    END;

    --带参数的游标
    DECLARE
       CURSOR c_emp(v_no1 NUMBER, v_no2 NUMBER) IS SELECT * FROM emp WHERE deptno = v_no1 OR deptno = v_no2;
       v_row emp%ROWTYPE;
    BEGIN
      OPEN c_emp(10,20);--传入部门编号deptno
      LOOP
       FETCH c_emp INTO v_row;
       EXIT WHEN c_emp%NOTFOUND;
       dbms_output.put_line(v_row.ename||'=='||v_row.job);
      END LOOP;
      CLOSE c_emp;
    END;

    6.异常
    exception---when----then
    --预定义异常
    DECLARE
      v_num NUMBER(3);
      BEGIN
       v_num := 10000;
       EXCEPTION
        WHEN value_error THEN
         v_num := 999;
         dbms_output.put_line(v_num);
      END;

    --自定义异常
       DECLARE
       V_AGE NUMBER(8) := &NUM;
       EXC_AGE EXCEPTION; --声明异常
      BEGIN
       IF V_AGE > 150 THEN
        RAISE EXC_AGE;
       END IF;
      EXCEPTION
       WHEN EXC_AGE THEN
        RAISE_APPLICATION_ERROR(-20001, 'illegal age');
      END;

    二.存储过程
    概念:一段被命名的plsql,预编译到了数据库中
    语法:
         create or replace procedure 存储过程名字(参数1 [in]/out 数据类型)
             as | is
             begin

            end;
    例子1:
      --存储过程,打印指定员工的年薪
      create or replace procedure pro_emp_sal(v_no number) is
      v_sal number(8, 2);
    begin
      select sal * 12 + nvl(comm, 0) into v_sal from emp where empno = v_no;
      dbms_output.put_line(v_sal);
    end;
    --方法一调用存储过程
      call pro_emp_sal(7788);
    --方法二调用存储过程
    begin
      pro_emp_sal(7788);
    end;   

    例子2:带out参数的存储过程
    CREATE OR REPLACE PROCEDURE pro_emp_sal2(v_no NUMBER, v_yearsal OUT NUMBER) IS
    BEGIN
      SELECT sal*12 + NVL(comm,0) INTO v_yearsal FROM emp WHERE empno = v_no;
    END;
    --只能使用方式二调用
    DECLARE
      v_sal NUMBER(8,2);
      BEGIN
       pro_emp_sal2(7788,v_sal);
       dbms_output.put_line(v_sal);
      END;

    三.存储函数
    --存储函数
    CREATE OR REPLACE FUNCTION fun_emp_sal(v_no NUMBER)
    RETURN NUMBER
    IS
    v_sal NUMBER(8,2);
    BEGIN
      SELECT sal*12+NVL(comm,0) INTO v_sal FROM emp WHERE empno = v_no;
      RETURN v_sal;
      END;
      --使用存储函数
      BEGIN
       dbms_output.put_line(fun_emp_sal(7788));
       END;

    注:存储过程和存储函数的区别
    1、语法不同
    2、使用场景:一般存储函数多被存储过程使用,存储过程一般使用在项目和项目之间的数据交互
    3、存储函数可以直接在sql中使用,而存储过程不能
    select ename,sal,func_emp_sal(empno)  from emp;


    四.使用jdbc调用存储过程和存储函数
    1.BaseDao用于加载驱动和获取连接
    2.ProcedureDao用于调用存储过程
    3.TestDao用于测试

    举例:
    1.BaseDao用于加载驱动和获取连接
    public class BaseDao {
          //加载驱动
         static{
             try {
                 Class.forName("oracle.jdbc.OracleDriver");
             } catch (ClassNotFoundException e) {
                 e.printStackTrace();
             }
         }
        
         //获取连接
         public static Connection getConn() throws SQLException{
             String url="jdbc:oracle:thin:@192.168.92.8:1521:orcl";
             String user="qin";
             String password="qin";
             return DriverManager.getConnection(url, user, password);
         }
        
         public static void closeAll(ResultSet rs,Statement stmt,Connection conn){
             if(rs!=null){
                 try {
                     rs.close();
                 } catch (SQLException e) {
                     e.printStackTrace();
                 }
             }
             if(stmt!=null){
                 try {
                     stmt.close();
                 } catch (SQLException e) {
                     e.printStackTrace();
                 }
             }
             if(conn!=null){
                 try {
                     conn.close();
                 } catch (SQLException e) {
                     e.printStackTrace();
                 }
             }
         }
    }

    2.ProcedureDao用于调用存储过程
    public class ProcedureDao {
         public static Long  getSal(Long v_no){
             Connection conn = null;
             CallableStatement stmt=null;
             Long yearsal=0l;

            try {
                 conn=BaseDao.getConn();
                 stmt = conn.prepareCall("call pro_emp_sal2(?,?)");//调用存储过程
                 stmt.setLong(1, v_no);
                 stmt.registerOutParameter(2, OracleTypes.NUMBER);    //指定参数的数据类型
                 stmt.execute();
                 yearsal = stmt.getLong(2);
             } catch (SQLException e) {
                 e.printStackTrace();
             }
             return yearsal;
         }
    }

    3.TestDao用于测试
    public class TestDao {
         public static void main(String[] args) {
             CursorDao.getEmp(10l);
         }
    }

    五.触发器
    1.--创建添加数据引发操作的触发器
    CREATE OR REPLACE TRIGGER tri_add_emp
    AFTER
    INSERT ON emp

    BEGIN
      dbms_output.put_line('增加了一条数据');
    END;

    --增加一条数据,看是否会触发
    INSERT INTO emp(empno,ename,deptno) VALUES(1,'tom',10);

    2.--系统时间引发的触发器
    CREATE OR REPLACE TRIGGER tri_emp
    BEFORE
    DELETE OR UPDATE OR INSERT
    ON emp
    FOR EACH ROW

    DECLARE
      v_dateStr VARCHAR2(20);
    BEGIN
      SELECT to_char(SYSDATE,'yyyy-mm-dd') INTO v_dateStr FROM dual;
      IF v_dateStr = '2017-09-20' THEN
       raise_application_error(-20002,'今天系统维护');
       END IF;
      END;
     
      --测试是否能引发触发器
      INSERT INTO emp(empno,ename,deptno) VALUES (3,'jerry',10);

    六.误删除数据恢复语句
    create table tableName_bak
    as
    select * from tableName as of TIMESTAMP to_timestamp('20081126 103435','yyyymmdd hh24miss');

  • 相关阅读:
    获取SqlServer数据库、表(字段、索引..)、视图、存储过程等信息脚本
    C# 资源Resources.resx中文件的获取、读取及复制
    C# 解锁从互联网下载的需要右键属性“解除锁定”的文件
    SqlServer根据生日计算年龄,精确到年(岁)月日小时分秒
    PHP设计模式—模板方法模式
    YII2中beforeSave和TimestampBehavior的使用,自动更新创建时间,更新时间
    YII2中like查询单边匹配%
    开发中 利用 spring利用扩展点 applicationContextAware,BeanNameAware实现模板+策略模式
    Spring RestTemplate调用接口乱码解决
    设计模式学习
  • 原文地址:https://www.cnblogs.com/huguangqin/p/7563368.html
Copyright © 2011-2022 走看看