oracle PL/SQL基础学习

–if else语句

declare
  v_sal NUMBER(7,2);
BEGIN
  SELECT sal into v_sal from emp
  where ename='SCOTT';
  DBMS_OUTPUT.PUT_LINE('SCOTT工资:'||v_sal);
  if v_sal<1000 then
      dbms_output.PUT_LINE('scott1000');
  else
    if 1000<=v_sal and v_sal<2000 then
      dbms_output.PUT_LINE('scott工资在1000到2000之间');
    else
      dbms_output.PUT_LINE('scott工资高于2000');
    end if;
  end if;
end;

–测试dmbs,在DBMS Output下,点击左上角按钮开启dmms set

serveroutput on
exec dbms_output.put_line('scotts');

–if elsif else 语句

declare
  v_sal number(7,2);
begin
  select sal into v_sal from emp
  where ename='SCOTT';
  dbms_output.put_line('scott的工资是'||v_sal);
  if v_sal<1000 then
    dbms_output.put_line('工资低于1000');
  elsif v_sal>1000 and v_sal<=2000 then
    dbms_output.put_line('工资在1000到2000之间');
  else
    dbms_output.put_line('工资大于2000');
  end if;
end;

–case when

declare
  v_sal number(7,2);
begin
  select sal into v_sal from emp
  where ename='SCOTT';
  dbms_output.put_line('scott`s sal is'||v_sal);
  case 
    when v_sal<1000 then
      dbms_output.put_line('scott sal low than 1000');
    when v_sal>1000 and v_sal<=2000 then
      dbms_output.put_line('scott sal between 1000 and 2000');
    else
      dbms_output.put_line('scott sal height than 2000');
  end case;
end;

–loop循环

declare
  v_i number := 1;
  v_s number := 0;
begin
  loop
    exit when v_i>100;
      v_s := v_s+v_i;
      v_i:=v_i+1;
  end loop;
  dbms_output.put_line(v_s);
end;

–exception

/*
  异常分为预定义异常、非预定义异常、自定义异常
  预定义异常:由oracle定义,异常发生时自动触发,大约20个左右
  非预定义异常:由用户关联oracle提供的异常代码,用PRAGMA EXCEPTION_INIT(异常名,异常代码);
  自定义异常:必须声明,并且用RAISE语句显式引发
*/
/*
  EXCEPTION
    WHEN name1 [OR name2] THEN
     语句1
    WHEN name3 [OR name4] THEN
     语句2
    ...
    WHEN OTHERS THEN
      语句3
  END;
*/

–预定义异常

declare
  v_name emp.ename%type;
begin
  select ename into v_name from emp
  where empno = &emp_no;
    dbms_output.put_line('employee name:'||v_name);
  exception
    when no_data_found then
      dbms_output.put_line('not exist this employee,please input'||v_name);
end;
--select empno from emp where ename='SCOTT';

–非预定义异常

declare
  e_null_error EXCEPTION;
  pragma exception_init(e_null_error,-1400);--由pragma exception_init()关联
begin
  insert into dept values(null,'demo1','bj1');
exception
  when e_null_error then
    dbms_output.put_line('cannot insert NULL into the table of dept');
end;

–自定义异常

declare
  v_sal number;
  e_sal_error exception;
begin
  select sal into v_sal from emp where empno=&emp_no;
  if v_sal>=2500 then
    dbms_output.put_line('this employee1`s sal is'||v_sal);
    raise e_sal_error;--由raise手动引发,自定义异常不一定是错误,可能是程序员根据编程和调试需要而为特殊情况所定义的
  end if;
exception
  when e_sal_error then
    dbms_output.put_line('this employee`s sal more than 2500');
end;

–过程和函数

/*
  以上为匿名plsql块,缺点是每次执行都需要被重新编译,并且不能被存储在数据库中
  过程与函数式命名的plsql块,被存储在数据库中,可以被其他plsql块使用
  格式:create [or replace] procedure procedure_name(arg1 [IN | OUT ] argtype1,arg2 [IN | OUT ] argtype2...)
          as | is
            声明部分
          BEGIN
            执行部分
          EXCEPTION
            异常部分
          END procedure_name;
*/
create or replace procedure query_emp
  (v_no IN emp.empno%type,
   v_name OUT emp.ename%type,
   v_sal OUT emp.sal%type)
IS
  e_sal_error exception;
begin
  select ename,sal into v_name,v_sal from emp where empno = v_no;
  if v_sal>=2500 then
    DBMS_OUTPUT.PUT_LINE('this employee`s sal is'||v_sal);
    raise e_sal_error;
  end if;
exception
  when no_data_found then
    DBMS_OUTPUT.PUT_LINE('there is not exist this employee'||v_no);
  when e_sal_error then
    DBMS_OUTPUT.PUT_LINE('this employee`s sal more than 2500');
end query_emp;
--  sql/plus中
variable a1 varchar2(16);
variable a2 number;
execute query_temp(7788, :a1, :a2);
--PL/SQL块中
declare
  v_a1 emp.ename%TYPE;
  v_a2 emp.sal%TYPE;
begin
  query_emp(v_name => v_a1,v_sal => v_a2, v_no =>7788);
end;
--返回值:函数有且只有1个返回值,而存储过程可以通过OUT参数返回多个
--调用: 函数可以在查询语句中直接调用,而存储过程必须单独调用
--函数一般用来计算并返回一个计算结果,而存储过程一般是用来完成特定的数据操作

–自定义错误代码及消息文本

--为应用程序提供一种与oracle交互、比较自由的方法(并不一定是错误,可能仅仅为了提示)
--RAISE_APPLICATION_ERROR(ERROR_CODE,MESSAGE[, TRUE | FALSE])
--ERROR_CODE:自己定义的代码 范围为(-20000~-20999之间)
--MESSAGE:消息文本,第三个参数为可选,默认FALSE,如果为false,则用当前message代替错误消息栈中的消息,反之。


create or replace procedure query_comm_if_null
(v_no in emp.empno%TYPE)
is
  v_comm emp.comm%TYPE;
begin
  select comm into v_comm from emp where empno = v_no;
  if v_comm is NULL OR v_comm = 0 then
    RAISE_APPLICATION_ERROR(-20001, 'this employee has not comm');
  end if;
exception
  when NO_DATA_FOUND then
    dbms_output.put_line('there is not exist this employee'||v_no);
end query_comm_if_null;
--调用
declare
  e_comm_null exception;
  pragma exception_init(e_comm_null,-20001);
begin
  dbms_output.put_line('employee num is 5678');
  <<block_1>>
    begin
      query_comm_if_null(5678);
    end block_1;
    dbms_output.put_line('employee num is 7788');
    <<block_2>>
    begin
      query_comm_if_null(7788);
    exception
      when e_comm_null then
        dbms_output.put_line('add comm for this employee');
    end block_2;
end;

–游标

--分为显式游标和隐式游标
--每个用户回话中可以打开多个游标,其数量由数据库初始化参数文件中的OPEN_CURSORS参数定义
/*
一、声明游标
CURSOR cursor_name[(arg1 arg1_type [,arg2 arg2_type]......)]参数只能是输入参数
[RETURN return_datatype]
select_statement;


二、打开游标
OPEN cursor_name[(arg1 arg_datatype[,arg2 arg2_type])......];


三、提取游标
游标打开后,游标指针指向结果集第一行,如果要提取结果集中的数据,就需要提取游标,语法:
FETCH cursor_name INTO {variable_list | record_variable};


该语句执行时,每次返回一个数据行,然后指针自动移动到下一个数据行,当检索到最后一行时候,再执行该语句
操作将失败,并使游标属性%notfound值为true


四、关闭游标
当提取和处理完游标后,应该及时关闭游标,以释放他所占用系统资源:
CLOSE cursor_name;




*/


declare
  type DeptRecord IS RECORD
    (deptno dept.deptno%TYPE,
     dname dept.dname%TYPE,
     loc dept.loc%TYPE
    );
    v_deptrecord DeptRecord;
    v_dept_name dept.dname%TYPE;
    v_dept_loc dept.loc%TYPE;
    CURSOR c1 --声明游标
    IS
      select dname,loc from dept where deptno <= 10;
    Cursor c2(v_dept_no number) --有参数游标
    IS
      select dname,loc from dept where deptno <= v_dept_no;
    CURSOR c3(v_dept_no number) --有返回数据类型游标
      return DeptRecord
    IS
      select deptno,dname,loc from dept where deptno <= v_dept_no;
    CURSOR c4(v_dept_no number)
    IS
      select deptno,dname,loc from dept where deptno <= v_dept_no;
    v_dept_rec c4%ROWTYPE; --基于游标定义记录变量,比DeptRecord方便
begin
  OPEN c1;
  LOOP
    FETCH c1 into v_dept_name,v_dept_loc; --提取游标
    if c1%found then
      dbms_output.put_line('c1:'||v_dept_name||' '||v_dept_loc);
    else
      dbms_output.put_line('c1:'||'process over!!');
      exit;
    end if;
  end loop;
  open c2(20);
  loop
    fetch c2 into v_dept_name,v_dept_loc;
    exit when c2%notfound;
    dbms_output.put_line('c2:'||v_dept_name||' '||v_dept_loc);
  end loop;
  open c3(v_dept_no=>30);
  loop
    fetch c3 into v_deptrecord;
    exit when c3%notfound;
      dbms_output.put_line('c3:'||v_deptrecord.deptno||' '||v_deptrecord.dname);
    end loop;
    open c4(40);
    loop
      fetch c4 into v_dept_rec;
      exit when c4%notfound;
      dbms_output.put_line('c4:'||v_dept_rec.deptno||' '||v_dept_rec.dname);
    end loop;
    close c1;
    close c2;
    close c3;
    close c4;
end;
--游标FOR循环
--FOR index_variable IN cursor_name[(value1[,value2]......)] LOOP
--语句段
--END LOOP


declare
  CURSOR c1(v_dept_no NUMBER DEFAULT 10)
    IS
      SELECT deptno,dname FROM dept WHERE deptno <= v_dept_no;
    BEGIN
      DBMS_OUTPUT.PUT_LINE('arg is 30');
      FOR c1_rec IN c1(30) LOOP
        DBMS_OUTPUT.PUT_LINE('c1:'||c1_rec.deptno||' '||c1_rec.dname);
      END LOOP;
      DBMS_OUTPUT.PUT_LINE('use v_dept_no default arg 10');
      FOR c1_rec IN c1 LOOP
        DBMS_OUTPUT.PUT_LINE('c1:'||c1_rec.deptno||' '||c1_rec.dname);
      END LOOP;
END;

–使用游标更新或删除数据

/*
  如果用显式游标更新或删除数据,则必须要求游标查询语句中使用FOR UPDATE选项,以便在打开游标时
  锁定游标结果集所在数据库表中对应的数据行,语法:
  SELECT column_list FROM table_list FOR UPDATE
  使用FOR UPDATE打开游标之后就可以在UPDATE和DELETE语句中使用WHERE OF 子句,修改或删除游标结果集
  中当前行所对应的数据了,语法:
  WHERE CURRENT OF cursor_name
*/
declare
  v_emp_rec emp%ROWTYPE;
  CURSOR c1
    is
      select * from emp FOR UPDATE;
  begin
    open c1;
    LOOP
      fetch c1 into v_emp_rec;
      exit when c1%notfound;
      if v_emp_rec.deptno>=30 then
        update emp set comm=800 
        where current of c1;
      end if;
    end loop;
    commit;
    close c1;
end;

select * from emp where deptno>=30

–触发器

/*
  1.触发器不接受参数
  2.一个表上最多可以有12个触发器,但同一时间、同一事件、同一类型的触发器只能有一个,各个触发器之间不能相互矛盾
  3.在一个表上触发器越多,对在该表上DML操作的性能影响就越大
  4.触发器最大为32KB
  5.在DML触发器中只能使用DML语句(SELECT,INSERT,UPDATE,DELETE)
  6.在系统触发器中只能包含DDL语句(CREATE,ALTER,DROP)
  7.触发器中不能包含事物控制语句(COMMIT,ROLLBACK,SAVEPOINT)
  8.在触发器中调用的任何过程、函数都不能使用事务控制语句
  9.在触发器主体中不能声明任何LONG和BLOB变量
  10.不同触发器(DML触发器、INSTEAD OF触发器、系统触发器)语法格式和作用都有较大区别
*/
--DML触发器
--定义在一个表和简单视图上的触发器,是常用的传统触发器
--语句级触发器
--语法格式:
--CREATE [OR REPLACE] TRIGGER tigger_name
--{BEFORE | AFTER} --触发时机
--{INSERT | UPDATE |DELETE} --触发事件
--[OR {INSERT |DELETE |UPDATE}......]
--ON table_name --制定触发对象,即该触发器被创建在那个表或视图上
--PL/SQL_block | CALL procedure_name; --制定触发器触发时候要执行的pl/sql程序块或使用
--CALL调用的子程序


create or replace trigger tr_emp_time
before insert
    or update
    or delete
  on emp
  begin
    if  (to_char(sysdate,'DAY') in ('星期六','星期日'))
      or (to_char(sysdate,'HH24') not between 8 and 18) then
        RAISE_APPLICATION_ERROR(-20001,'cannot change emp,because the time is not right');
    end if;
end;


update emp set comm=200 where deptno>20;
--行级触发器(可以对列值进行访问,在列明前加OLD.限定词表示变化前的值,
--          加NEW.表示边变化后的值,在PL/SQL块中使用时候还要加上:,
--          when 条件中不用加)
--语法:
/*
  CREATE [OR REPLACE] TRIGGER tigger_name
  {BEFORE | AFTER}
  {INSERT | DELETE | UPDATE [OF column1 [,column2,......]]}
  [OR {INSERT | DELETE |UPDATE [OF column3 [column4,......]]}]
  ON table_name
  FOR EACH ROW --表示该触发器为行级触发器
  [WHEN condition]
  PL/SQL_block | CALL procedure_name;
*/

create or replace trigger tr_emp_sal_comm
before 
  update OF sal,comm
  or delete
ON emp
FOR EACH ROW
WHEN (OLD.job='SALESMAN')
BEGIN
  CASE
    when updating('sal') then
      if :new.comm < :old.comm then
        raise_application_error(-20002,'sale man  sal cannot low');
      end if;
    when updating('comm') then
      if :new.comm < :old.comm then
        raise_application_error(-20003,'sale man`s comm cannot low');
      end if;
    when deleting then
        raise_application_error(-20004,'cannot delete the table of emp');
  end case;
end;

update emp set comm=200 where job = 'SALESMAN'
--INSTEAD OF触发器
/*
定义在复杂视图上的触发器
复杂视图特征:
1.具有集合操作符(UNION,UNION ALL,INTERSECT,NIMUS)
2.具有分组函数(MIN,MAX,SUM,AVG,COUNT等)
3.具有GROUP BY,CONNET BY,START WITH等子句
4.具有DISTINCT关键字
5.具有多表连接查询
*/
--查询触发器
select trigger_name,status from user_triggers where table_name='EMP'
--禁止触发器
ALTER TRIGGER tr_emp_time DISABLE;
--激活触发器
ALTER TRIGGER tr_emp_time ENABLE;
--禁止或激活表上所有触发器
--ALTER TABLE dept DISABLE/ENABLE ALL TRIGGER;
--重新编译触发器
ALTER TRIGGER tr_emp_time COMPILE;
--删除触发器
DROP TRIGGER tr_emp_time;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值