oracle--plsql块、存储过程、存储函数

一、pl/sql块

在sql语句中增加过程处理语句,使sql语句具有过程处理能力

语法:

declare --变量声明

begin

--代码逻辑

exception --异常处理

end;

--变量

--声明变量

变量名 类型(长度)

--变量赋值语法

变量名:= 变量值

declare

v_price number(10,2);

v_usenum number;

v_usenum2 number(10,2);

v_money number(10,2);

begin

v_price:=2.45;

v_usenum:=9231;

v_usenum2:=round(v_usenum/1000,2);

v_money:=v_price*v_usenum2;

--打印

DBMS_OUTPUT.put_line('金额:'||v_money);

end;

--从数据库中查询然后赋值

select 列名 into 变量名 from 表名 where 条件

declare

v_price number(10,2);

v_usenum number;

v_usenum2 number(10,2);

v_money number(10,2);

v_num0 number;--上月水表数

v_num1 number;--本月水表数

begin

v_price:=2.45;

--v_usenum:=9231; 水表字数

select usenum into v_usenum from t_account

where year = '2012' and month = '01'and owneruuid=1;

v_usenum2:=round(v_usenum/1000,2);

v_money:=v_price*v_usenum2;

--打印

DBMS_OUTPUT.put_line('金额:'||v_money);

end;

--属性类型(引用型 表名.列名%type)

处理数据库表数据时的首选写法

完全不用改代码,自动适配新类型

select * from t_account

declare

v_price number(10,2);

v_usenum t_account.usenum%type;

v_usenum2 number(10,2);

v_money number(10,2);

v_num0 t_account.num0%type;--上月水表数

v_num1 t_account.num1%type;--本月水表数

begin

v_price:=2.45;

--从数据库提取

select usenum into v_usenum from t_account

where year = '2012' and month = '01'and owneruuid=1;

v_usenum2:=round(v_usenum/1000,2);

v_money:=v_price*v_usenum2;

--打印

DBMS_OUTPUT.put_line('金额:'||v_money);

end;

--数据类型(记录型 表名%rowtype)

它是存储一整行数据的记录型类型,是 %TYPE 的升级版

  1. 查询表中一整行数据时(最常用)

不用单独声明 g_id、g_name、g_price 三个变量,一个变量搞定所有列。

  1. 表结构修改时(自动适配)

如果给表加一列、修改价格精度,代码完全不用改,%ROWTYPE 自动同步新结构。

  1. 插入 / 更新整行数据时

declare

v_price number(10,2);

v_usenum2 number(10,2);

v_money number(10,2);

v_account t_account%rowtype;--台账行记录类型

begin

v_price:=2.45;

--从数据库提取

select * into v_account from t_account

where year = '2012' and month = '01'and owneruuid=1;

v_usenum2:=round(v_account.usenum/1000,2);

v_money:=v_price*v_usenum2;

--打印

DBMS_OUTPUT.put_line('金额:'||v_money);

end;

二、异常

发生异常后,语句停止执行,控制权转移到pl/sql 异常处理部分,有两种异常

预定义异常:当pl/sql程序违法oracle规制或超过系统现在模式引发

自定义异常:在pl/sql块的声明部分定义异常,自定义的异常通过raise语句显示引发

exception

when 异常类型 then

异常处理逻辑

--条件判断

if 条件 then

业务逻辑

end if;

if条件 then

业务逻辑

else

业务逻辑

end if;

if 条件 then

业务逻辑

elsif 条件 then 业务逻辑

else

业务逻辑

end if;

设置三给等级的水费5吨以下2.45元,5-10吨3.45 超过10吨4.45

declare

v_price number(10,2);

v_price2 number(10,2);

v_price3 number(10,2);

v_usenum2 number(10,2);

v_money number(10,2);

v_account t_account%rowtype;--台账行记录类型

begin

v_price:=2.45;

v_price2:=3.45;

v_price3:=4.45;

--从数据库提取

select * into v_account from t_account

where year = '2012' and month = '01'and owneruuid=1;

v_usenum2:=round(v_account.usenum/1000,2);

--水费计算

if v_usenum2<=5 then

v_money:=v_price*v_usenum2;

elsif v_usenum2>5 and v_usenum2<=10 then

v_money := v_price2*(v_usenum2 - 5)+ v_price*5;

else

v_money := v_price*5+v_price2*5+v_price3*(v_usenum2-10);

end if;

--打印

DBMS_OUTPUT.put_line('金额:'||v_money);

end;

三、循环

1.无条件循环

loop

--循环语句

end loop;

输出从1到100个数

declare

v_num number:=1;

begin

loop

dbms_output.put_line(v_num);

v_num:=v_num+1;

if v_num>100 then

exit;

end if;

end loop;

end;

2.有条件循环

while 条件

loop

end loop;

输出从1到100个数

declare

v_num number;

begin

v_num := 1;

while v_num<=100

loop

dbms_output.put_line(v_num);

v_num:=v_num+1;

end loop;

end;

3.for循环

declare

begin

for v_num in 1..100

loop

dbms_output.put_line(v_num);

end loop;

end;

四、游标

游标是系统给用户开设的一个数据缓冲区,存放sql语句执行的结果,可以把游标理解成pl/sql的一个结果集

语法:

--声明

cursor 游标名称 is sql语句

--使用游标语法

open 游标名称

loop

fetch 游标名称 into 变量

exit when 游标名称%notfound --代表游标走到底了

end loop;

close 游标名称

打印业主类型为1的价格表

select * from t_pricetable where ownertypeid = 1

--游标输出结果集

declare

cursor cur_pricetable is select * from t_pricetable where ownertypeid = 1; --声明变量

v_pricetable t_pricetable%rowtype;

begin

open cur_pricetable;--打开游标

loop

fetch cur_pricetable into v_pricetable;--提前数据

exit when cur_pricetable%notfound;--退出循环

DBMS_OUTPUT.PUT_LINE('价格'||v_pricetable.price);

end loop;

close cur_pricetable;

end;

--带参数的游标

declare

cursor cur_pricetable(v_ownertype) is select * from t_pricetable where ownertypeid = v_ownertype; --声明变量

v_pricetable t_pricetable%rowtype;

begin

open cur_pricetable(1);--打开游标,数字是ownertypeid对应类型,代表传进去的参数

loop

fetch cur_pricetable into v_pricetable;--提前数据

exit when cur_pricetable%notfound;--退出循环

DBMS_OUTPUT.PUT_LINE('价格'||v_pricetable.price);

end loop;

close cur_pricetable;

end;

--for循环带参数游标

declare

cursor cur_pricetable(v_ownertype) is select * from t_pricetable where ownertypeid = v_ownertype; --声明变量

v_pricetable t_pricetable%rowtype;

begin

for v_pricetable in cur_pricetable(1) --数字是ownertypeid对应类型,代表传进去的参数

loop

DBMS_OUTPUT.PUT_LINE('价格'||v_pricetable.price);

end loop;

end;

五、存储函数

存储函数又称自定义函数,可以接受一个或多个参数,返回一个结果,用pl/sql进行逻辑处理

语法:

create [or replace] function 函数名称

(参数名称 参数类型,参数名称 参数类型,...)

return 结果变量数据类型

IS

变量声明部分;

begin

逻辑部分

return 结果变量;

exception 异常处理部分

end;

--创建存储函数,根据地址id查询地址名称

create or replace function fn_getaddress1

(v_id number)

return varchar2

IS

v_name varchar2(30);

begin

select name into v_name from t_address where id =v_id; --将查询到name的结果存入变量v_name中

return v_name;

end;

--存储函数测试

select fn_getaddress1(3) from dual;

--应用

查询业主id,业主名称,业主地址,用存储函数就可以实现,不用多表关联

select * from t_owners

select * from t_address

select ow.id,ow.name,ad.name from t_owners ow,t_address ad where ow.addressid = ad.id --多表的

select id,name,fn_getaddress1(addressid)from t_owners;--存储函数的

六、存储过程

业务必须全部成功或全部失败

存储过程是命名的pl/sql块,存储于数据库中,是数据库对象的一种,应用程序可以调用存储过程,执行相应的逻辑

存储过程与存储函数的区别

1.存储函数中有返回值,必须返回,存储过程没有返回值,可以通过传出参数返回多个值

2.存储过程可以在select语句中直接使用,而存储过程不能,过程多数是被应用程序所调用

3.存储过程一般是封装一个查询结果,而存储过程一般可以封装一段事务代码。

create or replace procedure 存储过程名称

(参数名 类型,参数名 类型)

is|as

变量声明部分

begin

逻辑部分

exception 异常处理部分

end;

--过程参数三种模式

in 传入参数(默认)

out 传出参数,主要用于返回程序运行结果

in out 传入传出参数

--创建不带传出参数的存储过程:添加业主信息,可以用序列

select * from owners

create sequence seq_ownersid start with 11;

create or replace procedure pro_insert

(v_name varchar2,v_addressid number,v_housenumber varchar2,v_waternumber varchar2,v_ownertypeid number )

is

begin

insert into t_owners values(seq_ownersid.nextval,v_name,v_addressid,v_housenumber,v_waternumber,sysdate,v_ownertypeid);

commit;

end;

调用存储过程

写法1:

call pro_insert ('测试','10','1-10','345',1)

写法2:

begin

pro_insert ('测试1','10','1-10','345',1);

end;

--创建带参数存储过程

create or replace procedure pro_insert1

(v_name varchar2,

v_addressid number,

v_housenumber varchar2,

v_waternumber varchar2,

v_ownertypeid number,

v_id out number

)

is

begin

--对传出参数赋值

select seq_account.nextval into v_id from dual;

insert into t_owners values(v_id,v_name,v_addressid,v_housenumber,v_waternumber,sysdate,v_ownertypeid);

commit;

end;

调用

declare

v_id number;

begin

pro_insert1 ('测试3','10','1-10','345',1,v_id);

dbms_output.put_line(v_id);

end;

七、触发器

一个与表关联的,存储的pl/sql程序,每当一个特定的数据操作语句在指定表上发出时,oracle自动执行触发器中定义的语句序列

可用于:

数据确认,实施复杂的安全性检查,做审计,跟踪表上所做的数据操作等,数据的备份和同步

分类

前置触发器(before)

后置触发器(after)

创建语法

create [or replace] trigger 触发器名称

before | after

delete\]\[\[or\]insert\]\[\[or\]update \[of 列名\]

on 表名

for each row\]\[where(条件)\] -- for each row表明是行级触发器 declare ... begin plsql块 end; --触发器中触发语句与伪记录变量的值(前置触发器可以改这个伪列的值,后置触发器不能修改只能使用) 分为行级触发器和语句触发器,语句触发器没有:old和:new insert :old 所有字段都是空(null) :new 将要插入的数据 update :old 更新以前该行的值 :new 更新后的值 delete :old 删除以前该行的值 :new 所有字段都是空 --前置触发器 当用户输入本月累计表数后,自动计算出本月使用数 select \* from t_account for update create or replace trigger tri_account_num1 before update of num1 on t_account for each row declare begin --通过伪记录变量修改usenum字段的值 :new.usenum:= :new.num1-:new.num0; end; --后置触发器 当前用户修改了业主名称的时间时记录修改前与修改后的值 --创建记录表 create table t_owners_log( updatetime date, ownerid number, oldnum varchar2(30), newnum varchar2(30) ); --创建触发器 create or replace trigger tri_after after update of name on t_owners for each row declare begin --向日志表插入 insert into t_owners_log values(sysdate,:new.id,:old.name,:new.name); end; select \* from t_owners for update --当前窗口能看到日志表里有数据,但是别的窗口看不到,要commit后才能看到 select \* from t_owners_log commit;

相关推荐
fire-flyer2 小时前
ClickHouse系列(四):压缩不是为了省磁盘,而是为了更快的查询
数据库·clickhouse
刘~浪地球2 小时前
Redis 从入门到精通(十四):内存管理与淘汰策略
数据库·redis·缓存
海边的Kurisu2 小时前
MySQL | 从SQL到数据的完整路径
数据库·mysql·架构
hINs IONN2 小时前
maven导入spring框架
数据库·spring·maven
CV艺术家2 小时前
mysql数据迁移到达梦数据库
java·数据库
枫叶林FYL2 小时前
【自然语言处理 NLP】工具学习与Agent架构:从函数调用到多智能体协作
数据库
不愿透露姓名的大鹏2 小时前
Oracle Undo空间爆满急救指南(含在线切换+更优方案+避坑指南)
linux·运维·数据库·oracle
做个文艺程序员2 小时前
MySQL 主从延迟根因诊断法
数据库·mysql
计算机安禾3 小时前
【数据结构与算法】第33篇:交换排序(二):快速排序
c语言·开发语言·数据结构·数据库·算法·矩阵·排序算法