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的基本原理与操作