oracle 学习之 PL/SQL
/* PL/SQL : Oracle内部语言 SQLServer的是:TSQL Procedural Language/SQL 是oracle在标准的SQL语言上的扩展,PL/SQL不仅允许嵌入SQL语言,还可以 定义变量和常量,允许使用条件语句和循环语句,允许使用例外处理各种错误,这样使得它的功能变得 更加的强大. 优点:提高应用程序的运行性能,模块化的设计思想,减少网络传输量,提高安全性 SQL语言:有两种SQL1992/SQL1996 没有循环控制结构 PL/SQL块由三个部分组成:定义部分,执行部分,例外处理部分 declare 定义部分 -- 定义常量,变量,游标,例外,复杂数据类型 begin 执行部分 -- 要执行的PL/SQL语句和SQL语句 exception 例外部分 -- 处理运行的各种错误 end; 调用过程 exec 过程名 call 过程名 */ --匿名块 --简单打印一句话 --打开显示 set serveroutput on ; begin dbms_output.put_line('Hello PL/SQL!'); end ; / /* 变量声明的规则 1 变量名不能够使用保留字 2 第一个字符必须是字母 3 变量名最多包含30个字符 4 不要与数据库的表或者列同名 5 每一行只能声明一个变量 常用的变量类型 1 binary_integer : 整数,主要用来计数而不是用来表示字段类型 2 number: 数字字符 3 char : 定长字符串 4 varchar2 : 变长字符串 5 data : 日期 6 long : 长字符串最长2GB 7 boolean : 布尔类型,可以取值true|false和null值 */ --声明变量 declare v_name varchar2(20) ; declare v_temp number(1); v_count binary_integer :=0; v_sal number(7,2) :=4000.00; v_date date :=sysdate ; v_pi constant number(3,2) :=3.14; v_valid boolean :=false; v_name varchar2(20) not null :='hello plsql' ; begin dbms_output.put_line('v_temp value :'||v_temp); end; --根据表中字段类型声明变量类型的 declare v_empno number(4); v_empno2 emp.empno%type; v_empno3 v_empno2%type; begin dbms_output.put_line('test'); end; /* 复杂变量 Table变量类型 : 集合 (表示集合时要自己定义的一个新的数据类型) Record变量类型 : 类 (代表实体,一条记录) */ --定义Table变量类型 --Table 变量类型(数组) declare type type_newname is table of emp.empno%type index by binary_integer; --声明一个数组类型 index by binary_integer 指系统创建一个主键索引,以引用记录表变量中的特定的行。 v_empnos type_newname ; --用数组类型定义变量 begin v_empnos(0) :=7369; v_empnos(2) :=7839; v_empnos(-1):=9999; dbms_output.put_line(v_empnos(-1)); end; --Record变量类型 declare type type_record_dept is record ( deptno dept.deptno%type, dname dept.dname%type, loc dept.loc%type ); v_temp type_record_dept ; begin v_temp.deptno :=50 ; v_temp.dname :='aaa'; v_temp.loc :='bj'; dbms_output.put_line(v_temp.deptno || ' ' || v_temp.dname); end; --使用%rowtype 声明record变量 declare v_temp dept%rowtype; --直接用一张表的行来定义record,表结构变化时record也在变 begin v_temp.deptno :=50; v_temp.dname :='aaa'; v_temp.loc :='bj'; dbms_output.put_line(v_temp.deptno||' '||v_temp.dname); end ; /* PL/SQL中的SQL语句 select 语句返回有且只有一条记录 */ --select语句 declare v_ename emp.ename%type; v_sal emp.sal%type; begin select ename,sal into v_ename,v_sal from emp where empno =7369; dbms_output.put_line(v_ename || ' '||v_sal); end; declare v_temp emp%rowtype; begin select * into v_emp from emp where empno=7369; dbms_output.put_line(v_temp.ename); end; --insert 语句 declare v_deptno dept.deptno%type :=10; v_dname dept.dname%type :='aaa'; v_loc dept.loc%type :='beijing' ; begin insert into dept2 values(v_deptno,v_dname,v_loc); commit; end; --update语句 declare v_deptno emp2.deptno%type :=10 ; v_count number; begin update emp2 set sal = sal/2 where deptno = v_deptno ; --select deptno into v_deptno from emp2 where empno = 7369; --select count(*) into v_count from emp2 ; dbms_output.put_line(sql%rowcount||'条记被影响'); commit ; end; --DDL语句 begin execute immediate 'create table t_temp(nnn varchar2(20) default "aaa")' ; end ; --语句块 declare v_name varchar2(20); begin v_name := 'jack' ; dbms_output.put_line(v_name); end; --带异常捕获的语句块 declare v_num number :=0 ; begin v_num :=2/v_num ; dbms_output.put_line(v_num); exception when others then dbms_output.put_line('error'); end; --分支语句 --if 取出7369的薪水,如果<1200,则输出'low',如果<2000则输出'middle',否则'high' declare v_sal emp.sal%type; begin select sal into v_sal from emp where empno=7369; if(v_sal<1200) then dbms_output.put_line('low'); elsif(v_sal<2000) then dbms_output.put_line('middle'); else dbms_output.put_line('high'); end if; end; --循环 (相当于do...while) declare i binary_integer :=1; begin loop dbms_output.put_line(i); i := i+1 ; exit when(i>=11); end loop; end; declare j binary_integer :=1; begin while j<11 loop dbms_output.put_line(j); j := j+1 ; end loop ; end; begin for k in 1..10 loop dbms_output.put_line(k); end loop; for k in reverse 1..10 loop dbms_output.put_line(k); end loop; end; --错误处理 declare v_temp number(4); begin select empno into v_temp from emp where deptno =10 ; exception when too_many_rows then dbms_output.put_line('太多记录了'); when others then dbms_output.put_line('error'); end; declare v_temp number(4); begin select empno into v_temp from emp where empno=2222; exception when no_data_found then dbms_output.put_line('没数据'); end; --错误记录 create table errorlog ( id number primary key, errcode number, errmsg varchar2(1024), errdate date ); create sequence seq_errorlog_id start with 1 increment by 1; declare v_deptno dept.deptno%type :=10 ; v_errcode number ; v_errmsg varchar2(1024) ; begin delete from dept where deptno=v_deptno; commit; exception when others then rollback; v_errcode :=SQLCODE; v_errmsg :=SQLERRM; insert into errorlog values(seq_errorlog_id.nextval,v_errcode,v_errmsg,sysdate); commit; end; select * from errorlog;
触发器
/* 触发器 trigger 触发器必须依附于表才能起作用 */ --创建日志表 emp_log,用于记录对表emp的所有操作日志 create table emp_log ( uname varchar2(20), action varchar2(10), atime date ); --创建触发器 /* 触发条件:insert|delete|update 对某张表做插入|删除|更新的操作 触发时间:after|before 操作之后|操作之前 触发行:each row 操作影响一行触发一次,不写表求一次操作触发一次 */ create or replace trigger trig after insert or delete or update on emp for each row begin if inserting then insert into emp_log(uname,action,atime) values(USER,'insert',sysdate); elsif updating then insert into emp_log(uname,action,atime) values(USER,'update',sysdate); elsif deleting then insert into emp_log(uname,action,atime) values(USER,'delete',sysdate); end if ; end; / --触发 update emp set sal=sal*2 where deptno=30; delete from emp where empno = 7369 ; --查看日志表 select * from emp_log; --? : 有外键关系时,主表中的主键存在外表的引用关系,因此不能随意更新,但可以用触发器解决这个问题 --如: update dept set deptno=99 where deptno=10 --删除触发器 drop trigger trig; create or replace trigger trig after update on dept for each row begin update emp set deptno = :NEW.deptno where deptno = :OLD.deptno ; end; / /* 通常一条update语句会产生新旧两个状态 :NEW代表新状态 :OLD代表旧状态 */ update dept set deptno=99 where deptno=10;