【Oracle】Oracle编程PLSQL

Oracle编程

一、PL/SQL

1、PL/SQL概述

PL/SQL(Procedure Language/SQL)是 Oracle 对 sql 语言的过程化扩展,使 SQL 语言具有过程处理能力。

基本语法结构

[declare 
	-- 声明变量
]

begin
	-- 代码逻辑 

[exception
	-- 异常处理
]

end;
2、变量
1)变量的声明与赋值
-- 声明变量
变量名 类型(长度);

-- 变量赋值
变量名:=变量值;
2)直接赋值

声明变量水费单价、水费字数、吨数、金额。

对水费单价、字数、进行赋值 。吨数根据水费字数换算,规则为水费字数除以

1000,并且四舍五入,保留两位小数。计算金额,金额 = 单价 * 吨数。

输出:单价、数量和金额。

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:=8012;
    
    -- 字数换算为吨数
    v_usenum2:= round( v_usenum/1000,2 );
    
    -- 计算金额
    v_money:=round(v_price*v_usenum2,2);
    
    -- 文字的输出
    dbms_output.put_line('金额:'||v_money); 
end;
2)select into 赋值
-- select into 语法
select 列名 into 变量名 from 表名 where 条件

select into 结果必须是一条记录 ,有多条记录和没有记录都会报错

declare
    v_price number(10,2);	-- 单价
    v_usenum number;		-- 水费字数
    v_num0 number;			-- 上月字数
    v_num1 number;			-- 本月字数
    v_usenum2 number(10,2);	-- 使用吨数
    v_money number(10,2);	-- 水费金额
begin
    -- 对单价进行赋值
    v_price:=3.45;
    
    -- select into赋值
    select usenum,num0,num1 
    into v_usenum,V_num0,V_num1 
    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||'上月字数:'||v_num0||'本月字数'||v_num1);
end;
3、属性类型
1)%TYPE 引用型

引用某表某的字段类型

对于不知道表内类型的数据,可以直接获取表内列的类型

declare
    v_price number(10,2);				-- 单价
    v_usenum T_ACCOUNT.USENUM%TYPE;		-- 水费字数
    v_num0  T_ACCOUNT.NUM0%TYPE;		-- 上月字数
    v_num1 T_ACCOUNT.NUM1%TYPE;			-- 本月字数
    v_usenum2 number(10,2);				-- 使用吨数
    v_money number(10,2);				-- 水费金额
2)%ROWTYPE 记录型

标识某个表的记录类型

一个记录型代表一行数据,类似java编程的实体类

declare
    v_price number(10,2);			-- 单价
    v_account T_ACCOUNT%ROWTYPE;	-- 台账行的记录型
    v_usenum2 number(10,2);			-- 使用吨数
    v_money number(10,2);			-- 水费金额
begin
    -- 对单价进行赋值
    v_price:=3.45;
    
    -- select into赋值
    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;
4、异常(例外)

发生异常后,语句将停止执行,控制权转移到 PL/SQL 块的异常处理部分

  • 预定义异常:Oracle预先定义的异常
    • NO_DATA_FOUND:使用 select into 未返回行
    • TOO_MANY_ROWS:执行 select into 时,结果集超过一行
  • 用户定义异常:用户定义异常,通过 RAISE 语句显式引发
-- 异常语法结构

exception
	when 异常类型 then
	异常处理逻辑
declare
    v_price number(10,2);			-- 水费单价
    v_usenum T_ACCOUNT.USENUM%type; -- 水费字数
    v_usenum2 number(10,3);			-- 吨数
    v_money number(10,2);			-- 金额 

begin
	-- 水费单价
    v_price:=2.45;
    
  	-- select into赋值
    select usenum into v_usenum from T_ACCOUNT
    where owneruuid=1 and year='2012' and month='01';
    
    -- 字数换算为吨数
    v_usenum2:= round( v_usenum/1000,3);
    
    -- 计算金额
    v_money:=round(v_price*v_usenum2,2);
    
    -- 信息输出
    dbms_output.put_line('金额:'||v_money);
    
-- 异常处理
exception
    when NO_DATA_FOUND then
    	dbms_output.put_line('未找到数据');
    when TOO_MANY_ROWS then
    	dbms_output.put_line('查询条件有误,返回多条信息');
end;
5、条件判断
-- 1、if
if 条件 then
	代码;
end if;

-- 2、if else
if 条件 then
	代码;
else
	代码;
end if;

-- 3、if elif eles
if 条件 then
	代码;
elsif 条件 then
	代码;
else
	代码;
end if;

设置三个等级的水费。 5 吨以下 2.45 元/吨,5 吨到 10 吨部分 3.45 元/吨,超过 10 吨部分 4.45 元/吨

根据使用水费的量来计算阶梯水费。

declare
    v_price1 number(10,2);		-- 不足 5 吨的单价
    v_price2 number(10,2);		-- 超过 5 吨不足 10 吨单价
    v_price3 number(10,2);		-- 超过 10 吨单价
    v_account T_ACCOUNT%ROWTYPE;-- 记录型
    v_usenum2 number(10,2);		-- 使用吨数
    v_money number(10,2);		-- 水费金额
begin
    -- 单价赋值
    v_price1:=2.45;
    v_price2:=3.45;
    v_price3:=4.45;
    
    -- select into赋值
    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_price1*v_usenum2;
    -- 第二个阶梯
    elsif v_usenum2>5 and v_usenum2<=10 then 
    v_money:=v_price1*5+v_price2*(v_usenum2-5); 
    -- 第三个阶梯
    else
    v_money:=v_price1*5+v_price2*5+v_price3*(v_usenum2-10);
    end if;
    
    -- 信息输出
    DBMS_OUTPUT.put_line('金额:'||v_money);

-- 异常处理
exception
    when NO_DATA_FOUND then
        DBMS_OUTPUT.put_line('没有找到数据');
    when TOO_MANY_ROWS then
        DBMS_OUTPUT.put_line('返回的数据有多行');
end;
6、循环
1)loop无条件循环
loop
	代码
	exit when 退出条件;
end loop;
-- 输出1至100
declare
	v_num number:=1;
begin 
	loop
 		dbms_output.put_line(v_num);
 		v_num:=v_num+1;
 		exit when v_num>100;
	end loop; 
end;
2)while条件循环
while 条件
loop
	代码
end loop;
-- 输出1至100
declare
	v_num number:=1;
begin 
	while v_num<=100
	loop
 		dbms_output.put_line(v_num);
 		v_num:=v_num+1;
	end loop; 
end;
3)for循环
for 变量 in 起始值 .. 终止值
loop
	代码
end loop;
-- 输出1至100
begin
	for v_num in 1 .. 100
	loop
		dbms_output.put_line(v_num); 
	end loop;
end;
7、游标
1)游标概述

存放 SQL 语句执行的结果集

2)游标的语法
-- 声明游标
cursor 游标名称 is SQL语句;

-- 使用游标
open 游标名称
loop
    fetch 游标名称 into 变量;
    exit when 游标名称%notfound;
end loop;
close 游标名称

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

declare
	-- 价格的行对象
	v_pricetable T_PRICETABLE%rowtype;
	-- 定义游标
	cursor cur_pricetable is select * from T_PRICETABLE where ownertypeid=1;
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 ;
3)带参数的游标

条件值有可能是在运行时才能决定的

类似于java的传参

declare
	-- 价格的行对象
	v_pricetable T_PRICETABLE%rowtype;
	-- 定义游标
	cursor cur_pricetable(v_ownertype number) is select * from T_PRICETABLE where ownertypeid=v_ownertype;
begin
	-- 打开游标
	open cur_pricetable(1);
	
    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 ;
4)for 循环提取游标值
declare
	-- 定义游标
	cursor cur_pricetable(v_ownertypeid number) is select * from T_PRICETABLE where ownertypeid=v_ownertypeid;
begin
	-- for循环
	for v_pricetable in cur_pricetable(3)
	loop 
		dbms_output.put_line('价格:'||v_pricetable.price); 
    end loop; 
end ;

二、存储函数

1、存储函数概述

存储函数又称为自定义函数。可以接收一个或多个参数,返回一个结果。

2、存储函数语法结构
create [ or replace ] function 函数名称
(参数名称 参数类型, 参数名称 参数类型, ...)
return 结果变量数据类型
is
	变量声明部分;
begin
	逻辑部分;
	return 结果变量;
[exception 
	异常处理部分]
end;
3、案例

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

create function fn_getaddress(v_id number) 
return varchar2
is
    v_name varchar2(30);
begin
    select name into v_name from t_address where id=v_id;
    return v_name;
end;
-- 测试函数
select fn_getaddress(3) from dual

-- 函数在子查询的应用
select id 编号,name 业主名称,fn_getaddress(addressid) 地址 from t_owners

三、存储过程

1、存储过程概述

存储过程没有return,但是可以通过传出函数,传出多个返回值

应用程序可以调用存储过程,执行相应的逻辑,对业务逻辑的封装。

与MVC框架的思想冲突

效率比MVC框架高

2、存储过程语法结构
create [ or replace ] procedure 存储过程名称
(参数名 类型, 参数名 类型, 参数名 类型)
is|as
    变量声明部分;
begin
    逻辑部分;
[exception 
	异常处理部分;]
end;

参数只指定类型,不指定长度

过程参数的三种模式:

  • IN :传入参数(默认)
  • OUT :传出参数 ,主要用于返回程序运行结果
  • IN OUT :传入传出参数
3、案例
1)不带传出参数的存储过程
-- 创建
create or replace procedure pro_owners_add 
(
    v_name varchar2,
    v_addressid number,
    v_housenumber varchar2, 
    v_watermeter varchar2,
    v_type number
)
is
begin
    insert into T_OWNERS values( seq_owners.nextval,v_name,v_addressid,v_housenumber,v_watermeter,sysdate,v_type);
    commit;
end;

-- 调用
-- 1、call
call pro_owners_add('赵伟',1,'999-3','132-7',1);
-- 2、begin end
begin
	pro_owners_add('赵伟',1,'999-3','132-7',1);
end;
// JDBC 调用存储过程
public static void add(Owners owners){
    java.sql.Connection conn = null;
    java.sql.CallableStatement stmt = null;
    try {
        conn = BaseDao.getConnection();
        stmt = conn.prepareCall("{call pro_owners_add(?,?,?,?,?)}");
        stmt.setString(1, owners.getName());
        stmt.setLong(2, owners.getAddressid());
        stmt.setString(3, owners.getHousenumber());
        stmt.setString(4, owners.getWatermeter());
        stmt.setLong(5, owners.getOwnertypeid());
        stmt.execute();
    } catch (SQLException e) {
    	e.printStackTrace();
    } finally {
    	BaseDao.closeAll(null, stmt, conn);
    }
}
2)带传出参数的存储过程
-- 创建
create or replace procedure pro_owners_add 
(
    v_name varchar2,
    v_addressid number,
    v_housenumber varchar2, 
    v_watermeter varchar2,
    v_type number,
    v_id out number -- 传出参数
)
is 
begin
    select seq_owners.nextval into v_id from dual;
    insert into T_OWNERS values(v_id,v_name,v_addressid,v_housenumber,v_watermeter,sysdate,v_type);
    commit;
end;

-- 调用
declare
	v_id number;
begin
	pro_owners_add('王旺旺',1,'922-3','133-7',1,v_id);
	DBMS_OUTPUT.put_line('增加成功,ID:'||v_id);
end;
// JDBC 调用存储过程
public static long add(Owners owners) {
    long id = 0;
    java.sql.Connection conn = null;
    java.sql.CallableStatement stmt = null;
    try {
        conn = BaseDao.getConnection();
        stmt = conn.prepareCall("{call pro_owners_add(?, ?,?,?,?,?)} ");
        stmt.setString(1, owners.getName());
        stmt.setLong(2, owners.getAddressid());
        stmt.setString(3, owners.getHousenumber());
        stmt.setString(4, owners.getWatermeter());
        stmt.setLong(5, owners.getOwnertypeid());
        // 册传出参数类型:表明第六个参数是传出参数
        stmt.registerOutParameter(6, OracleTypes.NUMBER);
        // 执行
        stmt.execute();
        // 执行后传出参数
        id = stmt.getLong(6);
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        BaseDao.closeAll(null, stmt, conn);
    }
    return id;
}

四、触发器

1、触发器概述

触发器是一个与表相关联的、存储的PL/SQL程序。

每当一个特定的操作,Oracle自动地执行触发器中定义的语句序列。

触发器可用于

  • 数据确认:录入的合法性验证
  • 实施复杂的安全性检查
  • 做审计,跟踪表上所做的数据操作等
  • 数据的备份和同步

触发器分类

  • 前置触发器(BEFORE):sql执行前执行触发器,可以修改sql执行的值
  • 后置触发器(AFTER):sql执行后执行触发器
2、创建触发器
create [or replace] trigger 触发器名
	before|after
	[delete][[or] insert] [[or] update[of 列名]]
	on 表名
	[for each row][when(条件)]
declare
	变量
begin
	代码
end;
  • FOR EACH ROW :作用是标注此触发器是行级触发器,不标注为语句级触发器
    • 行级触发器:每影响一行触发一次
    • 语句级触发器:每个语句只触发一次

在触发器中触发语句与伪记录变量的值

触发语句:old(修改前的行数据):new(修改后的行数据)
insert所有字段都是空(null)将要插入的数据
update更新以前该行的值更新后的值
delete删除以前该行的值所有字段都是空(null)
3、案例
1)前置触发器

当用户输入本月累计表数后,自动计算出本月使用数

CREATE OR REPLACE TRIGGER tri_account_update_num1
    before 
    UPDATE OF num1 
    ON t_account 
    FOR each ROW
DECLARE
BEGIN
	: new.usenum :=: new.num1 -: new.num0;
END;
2)后置触发器

当用户修改了业主信息表的数据时记录修改前与修改后的值

CREATE TRIGGER tri_owners_log
	after
	UPDATE OF name
	ON t_owners
	FOR each ROW
DECLARE
BEGIN
	INSERT INTO t_owners_log VALUES(SYSDATE,: old.id,: old.name,: new.name);
END;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/315553.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

004 Golang-channel-practice 左右括号匹配

第四题 左右括号打印 一个协程负责打印“&#xff08;”&#xff0c;一个协程负责打印“&#xff09;”&#xff0c;左右括号的数量要匹配。在这道题目里&#xff0c;我在main函数里进行了一个死循环。会产生一个随机数&#xff0c;随机数就是接下来要打印的左括号的数量。 例…

C#编程-了解线程的优先级

了解线程的优先级 控制线程行为的一个属性是它的优先级。.NET运行时环境基于它们的优先级执行线程。CPU一次仅执行一个线程。因此,处于执行的可运行状态的线程,排队等待轮到被处理器执行。线程是固定优先级调度的。带有优先级的每个线程在处理器的线程队列中有自己的位置。 …

Nginx多虚拟主机配置

最近写公司项目&#xff0c;需要和前端小伙伴对接&#xff0c;但是有时候只是后端的一个bug&#xff0c;也不好意思一直让前端小伙伴帮忙起服务&#xff0c;所以想着直接拿测试包在本地起一个前端环境&#xff0c;这样后续开发比较方便&#xff1b;因为公司项目有好几个&#x…

22款奔驰C260L升级ACC自适应巡航 解放双脚 出行更加安全

有的时候你是否厌倦了不停的刹车、加油&#xff1f;是不是讨厌急刹车&#xff0c;为掌握不好车距而烦恼&#xff1f; 如果是这样&#xff0c;那么就升级奔驰原厂ACC自适应式巡航控制系统&#xff0c;带排队自动辅助和行车距离警报功能&#xff0c;感受现代科技带给你的舒适安全…

<软考高项备考>《论文专题 - 63 质量管理(2) 》

2 过程1-规划质量管理 2.1 问题 4W1H过程做什么识别项目及其可交付成果的质量要求、标准&#xff0c;并书面描述项目将如何证明符合质量要求、标准的过程&#xff1b;作用&#xff1a;为在整个项目期间如何管理和核实质量提供指南和方向为什么做1、识别项目/产品质量要求和标…

Github项目推荐-Insomnia

项目地址 GitHub地址&#xff1a;GitHub - Kong/insomnia 官网&#xff1a;The Collaborative API Development Platform - Insomnia 项目简述 想必大家都知道PostMan吧。Insomnia可以说是PostMan的开源平替。页面ui很不错&#xff0c;功能强大&#xff0c;使用也比较方便。…

【ChatGPT-Share,国内可用】GPTS商店大更新:一探前沿科技的魅力!

使用地址&#xff1a;https://hello.zhangsan.cloud/list GPTS商店预览,王炸更新 精选应用&#xff1a; 系统内置应用&#xff1a; 绘画应用&#xff1a; 写作应用&#xff1a; 高效工具应用&#xff1a; 学术搜索和分析应用&#xff1a; 编程应用&#xff1a; 教育应…

开源项目CuteSqlite开发笔记(七):CuteSqlite释放BETA版本啦

经过大半年的开发&#xff0c;CuteSqlite程序代码不知不觉来到了6万行&#xff0c;有效行数4万行&#xff0c;CuteSqlite开发完成了一个小版本&#xff0c;进入下一个阶段&#xff0c;并于2024元旦释放BETA版本&#xff0c;有兴趣的朋友可以下载试用。 GitHub下载https://gith…

基于Docker Compose单机实现多级缓存架构2024

文章目录 一、环境参考二、专栏简介三、扩展 一、环境参考 NameVersionDocker Desktop for Windows4.23.0Openjdk8MySQL8.2.0Redis7.2Canal1.1.7OpenResty1.21.4.3-3-jammy-amd64Lua-Caffeine- 二、专栏简介 多级缓存实现过程比较长&#xff0c;将拆分为多个文章分步讲述。如…

【算法】信使(最短路问题)

题目 战争时期&#xff0c;前线有 n 个哨所&#xff0c;每个哨所可能会与其他若干个哨所之间有通信联系。 信使负责在哨所之间传递信息&#xff0c;当然&#xff0c;这是要花费一定时间的&#xff08;以天为单位&#xff09;。 指挥部设在第一个哨所。 当指挥部下达一个命令…

低维度向量的 Householder 反射变换 matlab 图示

1, 算法原理 设th 是一个弧度值&#xff0c; 令 Q | cos(th) sin(th) | | sin(th) -cos(th) | S span{ | cos(th/2.0) | } | sin(th/2.0) | x (x1, x2) 是一个平面上的二维向量 计算 y Qx Qx 则&#xff0c;y 是 x 通过有 S 定…

基于STM32F103和ESP8266的Wi-Fi模块驱动程序设计与优化

基于STM32F103和ESP8266的Wi-Fi模块驱动程序设计和优化是一个重要的任务&#xff0c;它将使STM32F103微控制器能够与ESP8266模块进行通信并实现无线网络连接。在本文中&#xff0c;我们将介绍如何设计和优化这样的驱动程序&#xff0c;并提供相关的代码示例。 1. 系统概述 Wi…

Ubuntu root 远程登录失败

背景&#xff1a;设置了两个系统用户&#xff1a;root、test&#xff1b;test可以登录&#xff0c;可以使用su 命令切换root用户登录成功&#xff1b; 但是直接用root登录&#xff0c;会报错。 查看登录日志的方法&#xff1a; 需要两个远程窗口&#xff0c;在第一个远程窗口…

案例103:基于微信小程序的移动网赚项目设计与实现

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder …

OCR字符识别:开始批量识别身份证信息

身份证信息批量识别OCR是一项解决方案&#xff0c;它能够将身份证照片打包成zip格式或通过URL地址进行提交&#xff0c;并能够识别照片中的文本信息。最终&#xff0c;用户可以将识别结果生成为excel文件进行下载。 API接口功能&#xff1a; 1. 批量识别&#xff1a;支持将多…

SmartX 超融合和分布式存储支持哪些信创硬件?如何选型配置?

为了推动 IT 基础架构国产化转型&#xff0c;不少用户都使用 SmartX 超融合和分布式存储构建信创云基础设施。其中&#xff0c;信创硬件的选型与配置往往是用户在规划与部署环节关注的重点&#xff1a;国产 CPU/存储怎么选&#xff1f;哪个系列/型号的性价比最高&#xff1f;如…

rpb/rpc文件说明与matlab读取

什么是rpb/rpc文件&#xff1f; rpb文件是用来存储用于遥感数据几何校正的RPC&#xff08;Rational Polynomial Coefficients &#xff09;模型的文件。类似的还有RPC文件&#xff0c;rpb与rpc文件只是格式不同&#xff0c;但包含的信息一致。其用于从图像坐标转换到地理坐标&a…

DartSDK下载

下载DartSDK(具有开发Dart命令行、服务器和非FlutterWeb应用程序所需的库和命令行工具(底层支持作用系统库)) 1.Homebrew环境 //brew --version 2.brew tap dart-lang/dart 3.brew install dart 修改host 下载成功 描述信息查看 AndroidStudio 引入配置 备注&#xff1a; …

x-cmd pkg | czg - git commit 智能生成工具

目录 简介首次用户功能特点竞品和相关作品进一步探索 简介 czg 源于 commitizen/cz-cli 交互插件中 cz-git 的延伸项目&#xff0c;重新使用 TypeScript 编写的零依赖独立的 Node.js 命令行工具。旨在使用交互友好的方式&#xff0c;辅助用户生成规范的 git commit message 约…

红队专题-Golang工具ChYing

Golang工具ChYing 招募六边形战士队员原chying工具代码分析并发访问控制并发 原子 写入读取 通道嵌套映射结构初始化启动代理服务器重启代理服务器 招募六边形战士队员 一起学习 代码审计、安全开发、web攻防、逆向等。。。 私信联系 原chying工具代码分析 前有 Chying 后有…