pl/sql程序基础知识:
pl/sql(procedural language/sql)oracle在标准sql上面的扩展,不仅简单的sql语句,还具有一般语言的特性:变量,常量,流程控制和循环,错误处理机制.是一个功能完善强大的过程化语言.
它的编程基本单位是块,复杂的功能都是多个块组成
我们来看看它的实列代码:
块结构: declear --定义部分,可选 /*定义部分--变量,常量,游标,异常,复杂数据类型*/ begin --执行部分 /*pl/sql语句和SQL语句;*/ exception --异常处理部分,风险程度.可选 /*异常处理部分*/ end; / --和java对比
pl/sql写的代码段实际上保存在数据库中的数据对象,根据功能不同分为过程,函数,触发器.这些代码端口,可以直接在java程序中直接调用
它的目的:将程序逻辑变为数据库逻辑,降低程序端复杂度,让更好的进行模块化编程
它的作用:作用:提高整个程序系统的性能,让模块化编程思想更简单实现,降低网络传输量.更安全
当然pl/sql也有缺点:它的移植性不好
存储过程:
我们来来说说原理:
执行特定的操作过程,有参数输入(in),有结果输出(out).,他们都在内部的传递过程要借助变量,把数据传递到执行部分,输出吧结果输出到调用部分
它是怎么增加的呢??请看下面代码
--=案例一 create or replace procedure mypro is --这里的命名不要和你的表名重合,ORA-04044: procedure, function, package, or type is not allowed here begin --执行部分 insert into c##scott.emp(empno,ename) values(‘20‘,‘donghot‘); end; / --完成并执行 --注意权限不足的问题insufficient privileges:每个用默认情况下只能在自己的方案下执行PLSQL /*注意: 1 你的数据要你的表结构匹配,(数据的个数要够,数据类型也要匹配):ORA-00947: not enough values 2 数据和你的约束匹配 */
通过上面的代码我们简单的认识了添加存储过程的代码;
pl/sql函数:
函数:用于返回特定的数据,在建立函数时,其头部必须包含return子句,在函数体内部必须包含return语句返回数据
案例:
-- 创建函数实例 create or replace function myfunction1(v_ename varchar2) return number is v_Ysal number(9,2); begin select sal*12+nvl(comm,0)*12 into v_Ysal from emp where ename=v_ename; return v_Ysal; end; --PLSQL中调用函数 var v_rev number; call myfunction1(‘SCOTT‘) into:v_rev; print v_rev; --java中调用函数 select myfunction1(‘SCOTT‘) from dual; rs.getInt(1);--获取返回值
pl/sql包:
逻辑上组合过程和函数,有规范和包体两部分组成
它是怎么调用的呢:
当调用包中的过程或是函数时,在过程和函数前面需要带有包名,如果是其他方案的包,还需要包前面带方案名;
来看看pl/sql增加包的案例吧!!!
--创建包实例 --创建包规范 create or replace package mypackage1 is procedure update_sal(name varchar2, newsal number); function annul_income(name varchar2) return number; end; / --此规范字包含了过程和函数的说明,但是没有过程和函数的实现代码. --所以需要重新建立包体,包体用于实现规范中的过程和函数 create or replace package body mypackage1 is procedure update_sal(name varchar2,newsal number) is begin update c##scott.emp set sal = newsal where ename=name; end; --函数开始 function annul_income(name varchar2) return number is return_salary number; begin select sal*12+nvl(comm,0) into return_salary from emp where ename=name; return return_salary; end; end; / --调用: --call/exec:包名.过程名(参数); call mypackage1.update_sal(‘SCOTT‘,199); --调用函数 var v_rev number; call mypackage1.annul_income(‘SCOTT‘) into:v_rev;--试验是call可以,exec不行 print v_rev;
触发器:
触发器是一个隐含执行的存储过程,当定义触发器是,必须要指定触发的事件和触发的操作,常用的触发事件包括insert,update,delete语句,触发操作对象实际是一个pl/sql块
怎么创建触发器??老样子,我们主要看代码:
create sequence seq01; create or replace trigger trig01 after insert or delete or update on dept begin if inserting then insert into emp(empno,ename,hiredate) values (seq01.nextval,‘insert‘, sysdate); elsif updating then insert into emp(empno,ename,hiredate) values (seq01.nextval,‘update‘, sysdate); elsif deleting then insert into emp(empno,ename,hiredate) values (seq01.nextval,‘delete‘, sysdate); end if; end;
变量:
标量类型:
标量类型的定义方式:
定义一个变长字符串 v_name varchar(10); 定义一个小数,切默认值是3.14 v_sal2 number(6,2):=3.14 定义一个小数 v_sal number(6,2); 定义一个日期类型 v_hiredate date; 定义一个特布尔变量,不能为空,初始值为false v_valid boolean not null default false
如以上,下面定义代码:
--通过员工编号,显示姓名,工资,个税 --税率为0.03 declare --声明变量 c_tax_rate number(3,2):=0.03; --v_name varchar2(5);--有可能小于查到的数据 v_name emp.ename%type;--和数据所在列的数据类型一样; 变量名 表名.列名%type v_sal number(7,2); v_tax_sal number(7,2); begin --执行 select ename,sal into v_name,v_sal from emp where empno=&no; --计算所得税 v_tax_sal:=v_sal*c_tax_rate; --输出 dbms_output.put_line(‘name:‘||v_name||‘ sal:‘||v_sal||‘ tax:‘||v_tax_sal); end;
符合变量类型:
数据集合变量有数组和集合;
pl/sql是干么用的??是用来保存多个值的变量,类和结构体的,如下可见....
declare type emp_record_type is record( --定义一个数据类型(记录类型):包含3个数据,有三个数据及其类型 name emp.ename%type, salary emp.sal%type, job emp.job%type); v_record emp_record_type; --定义一个变量,数据类型是emp_record_type begin select ename,sal,job into v_record from emp where empno=7788; dbms_output.put_line(‘ename:‘||v_record.name); dbms_output.put_line(‘sal:‘||v_record.salary); dbms_output.put_line(‘job:‘||v_record.job); end;
sql表:相当于数组.但是plsql下标可以为负数,并且元素下标没有限制
参照类型:
参照变量:是指用于存放数值指针的变量.通过使用参照变量,可以使得应用程序共享相同对象,从而降低占用空间
游标变量(ref cursor)(在我们工作中是用的最多的):
使用游标有声明和使用,声明时不需要指定相应的select语句,但是当使用游标时,需要指定select语句,从而和selct语句绑定
来个案例吧!!一看便知晓;条件:编写一个块,输入部门编号,显示部门所有员工和工资
对象类型变量(ref obj_type)
控制结构:
条件语句:
if...thien
if...thien...else
if...thien...elsif...else
create or replace procedure myProcedure08(sNo number) is
--create or replace procedure myProcedure
v_job emp.job%type;
begin
select job into v_job from emp where empno=sNo;
if v_job=‘PRESIDENT‘ then
update emp set sal=sal+1000 where empno=sNo;
--elseif v_job=‘MANAGER‘ then
--else if v_job=‘MANAGER‘ then
elsif v_job=‘MANAGER‘ then
update emp set sal=sal+500 where empno=sNo;
else
update emp set sal=sal+200 where empno=sNo;
end if;
end;
/
循环语句:
loop
while
for
这里我们就不代码举列了....
循序控制语句:
goto:goto语句(强烈建议不用),无用
null:null语句不会执行任何语句操作,并且会直接将执行传递到下一句;增加程序的可读性;
异常:
来看看处理Oracle常见的异常:
declare v_ename emp.ename%type; begin -- select ename into v_ename from emp where empno=&eno; dbms_output.put_line(‘name: ‘|| v_ename); exception when no_data_found then dbms_output.put_line(‘no found a‘); end;
例外:
处理与Oracle无关的例外
create or replace procedure ex_test(nu number) is begin update emp set sal=sal+1000 where empno=nu; end; create or replace procedure ex_test(nu number) is --定义一个例外 myex exception; begin update emp set sal=sal+1000 where empno=nu; --sql%不表示没有update if sql%notfound then raise myex; --SQL> --raise myex:触发myex end if; exception when myex then dbms_output.put_line(‘m没用用户更新‘); end;
视图:
视图就是一张虚拟表其内容由查询定义(SQL查询定义).和真的数据表一样,包含一系列带有名称的列和行数据.但是,视图并不在数据库中,以储存的数据值集形式存在啊
视图特性:不需要占用磁盘空间,表的区别;视图不能添加索引;使用视图可以简化复杂查询(多表联查);有更高的安全性,不同级别看不同的视图;视图本质上一张内存缓存表,所以和表不能重名
增加视图:create view 视图名 as select 语句 with [read only]
修改视图:create or replace view 视图名 as select 语句 with [read only]
删除视图:drop view 名字
序列:
oracle特有的,产生唯一的不间断的数字序列,用作表的主键
PL/SQL分页:
下面就不啰嗦了,直接上代码实现:
--oracle分页: select * from emp; select t1.*,rownum rn from (select * from emp) t1; select t1.*,rownum rn from (select * from emp) t1 where rownum<=10; --分页模版 select * from (select t1.*,rownum rn from (select * from emp) t1 where rownum<=10) where rn>=6; create or replace procedure Paging ( tableName in varchar2, --查询的表的名称 rowCount out number, --查询到的总记录数 pageSize in number, --每页显示数 pageCount out number, --总页码数 := rowCount/pageSize; pageNow in number, --当前页码数 page_cursor out PackagePaging.page_cursor --返回数据的结果集,jav边遍历然后输出到html页面中 ) is --定义变量 v_sql varchar2(1000); --定义两个整数,用于查询时候的起始数据行和结束数据行 v_begin number:=pageSize*(pageNow-1)+1; --起始的那个rowCount,起始那个数据的下标 v_end number:=pageSize*pageNow; --当前页的最后一个数据 --------------------------------------------- begin v_sql:=‘select * from (select t1.*,rownum rn from (select * from ‘||tableName||‘) t1 where rownum<=‘||v_end||‘) where rn>=‘||v_begin;--||‘;‘; --v_sql:=‘select * from emp‘; --给当前SQL语句的结果集绑定一个游标 open page_cursor for v_sql; -------------------------------------------- --查询一共有多少个结果 v_sql := ‘select count(*) from ‘|| tableName; --执行SQL语句,把返回的值赋值给rowCount execute immediate v_sql into rowCount; --计算pageCount if mod(rowCount,pageSize)=0 then pageCount:=rowCount/pageSize; else pageCount:=rowCount/pageSize+1; end if; --关闭游标 --close page_cursor; end;
PL/SQL无限分类:
如下:
drop table category;
--要点一:子类的pid必须是父类等于父类的id
create table category(
id number(10) primary key,
name varchar2(50),
pid number(10),
isleaf number(1),--0 代表非叶子节点,1代表叶子节点,
clevel number(2)
);
--cherub模拟数据
--要点二:模拟数据必须满足这个二维结构
insert into category values (1, ‘book1‘,0,0,0);
insert into category values (2, ‘book2‘,1,0,1);
insert into category values (3, ‘book3‘,2,1,2);
insert into category values (4, ‘book4‘,2,0,2);
insert into category values (5, ‘book5‘,4,1,3);
insert into category values (6, ‘book6‘,1,0,1);
insert into category values (7, ‘book7‘,6,1,2);
insert into category values (8, ‘book8‘,6,1,2);
insert into category values (9, ‘book9‘,2,0,2);
insert into category values (10, ‘book10‘,9,1,3);
create or replace procedure myProCat (
v_pid category.pid%type,
v_level binary_integer
) is
cursor c is select * from category where pid = v_pid; -- 要点:每次去满足这个条件,然后再把每条条数据中id传入到自己作为pid去查得下面的数据
v_preStr varchar2(1024) :=‘‘;
begin
for i in 0..v_level loop
v_preStr := v_preStr || ‘--‘;
end loop;
--要点三:递归函数的书写和调用
--要点四:pl/sql 增强for循环的问题
for v_category in c loop --就是一个增强的for循环,v_category的结果相当于是个集合
dbms_output.put_line( v_preStr||v_category.name);
if(v_category.isleaf=0) then
myProCat(v_category.id,v_level+1);
end if;
end loop;
end;
以上就是PL/SQL的基本原理与操作