首页 > 数据库 >Oracle数据库技术之PL/SQL语法和存储过程

Oracle数据库技术之PL/SQL语法和存储过程

时间:2022-10-20 15:34:48浏览次数:49  
标签:存储 end -- begin put SQL Oracle PL dbms

一、课程目标

PLSQL语法(掌握)
存储函数(了解)
存储过程(掌握)
JAVA来调用oracle函数或过程(掌握)

二、PL/SQL基础语法

2.1 什么是PL/SQL

PL/SQL(Procedure Language/SQL)是 Oracle 对 sql 语言的过程化扩展,指在 SQL 命令语言中增加了过程处理语句(如分支、循环等),使 SQL 语言具有过程处理能力。把 SQL 语言的数据操纵能力与过程语言的数据处理能力结合起来,使得 PLSQL 面向过程但比过程语言简单、高效、灵活和实用。

2.2 基本语法

[declare 
--声明变量
]
begin
--代码逻辑
[exception
--异常处理
]
end;

2.3 变量

声明变量和赋值
变量名 类型(长度);  
-- 1.基本类型
变量名:=变量值
--  1+1=2的案例
declare
a int:=1;
b int:=1;
c number;
begin
c:=a+b;
dbms_output.put_line(c);
end;
Select into 方式 赋值
select 列名 into 变量名 from 表名 where 条件

注意:结果必须是一条记录(不是一个值) ,有多条记录和没有记录都会报错

declare 
num_sal number;
var_name varchar2(20);
begin
select ename,sal into var_name,num_sal from emp where empno=7369;
dbms_output.put_line(var_name||'工资是:'||num_sal);
end;
  • 引用变量
    ​ 优点:1.用户不必查看表中各列的数据类型,即可查询到所需数据;
    ​ 2.对表中已经有的数据类型进行修改,不必考虑已定义的数据类型,和表中的一致;
    2.%Type类型
    -- 变量 表名.列名%type
    使用%Type关键字可以声明一个与指定名称相同的数据类型,它通常跟在指定列名的后面。

var_job emp.job%type -- 表示var_job和emp表下的job是同一个类型;


参考案例(同上做比较):

```plsql
select * from emp
declare
var_job emp.job%type;
var_name emp.ename%type;
begin
select ename,job into var_name,var_job from emp where empno=7369;
dbms_output.put_line(var_name||'职务:'||var_job);
end;

3.%rowtype类型

记录类型,用来存储从数据表查询到的一行的数据

语法:表变量名 表名%rowtype;

declare 
varEmp emp%rowtype;
begin
select * into varEmp from emp where empno= 7839;
dbms_output.put_line('员工'||varEmp.empno||'姓名'||varEmp.ename);
end;

从运行结果可以看到,变量varEmp和emp表的结构完全相同。

2.4 异常

在运行程序时出现的错误叫做异常发生异常后,语句将停止执行,控制权转移到 PL/SQL 块的异常处理部分

异常有两种类型:

预定义异常

当 PL/SQL 程序违反 Oracle 规则或超越系统限制时隐式引发

用户定义异常

用户可以在 PL/SQL 块的声明部分定义异常,自定义的

异常通过 RAISE 语句显式引发

2.4.1 预定义异常

Oracle 预定义异常 21 个

2.4.2 语法结构

exception
when 异常类型 then
异常处理逻辑

案例

declare
primary_iter exception; -- 定义一个自定义异常
pragma exception_init(primary_iter,-00001);
begin
insert into emp(empno,ename)values(7369,'sss');
exception
when primary_iter then
dbms_output.put_line('主键不能重复');
end;

2.5 条件判断

2.5.2 单分支

if 条件 then
业务逻辑
end if;
declare
vnum number:=#
begin
if vnum=1 then
dbms_output.put_line('成功登录');
end if;
end;

2.5.2 if else

if 条件 then
业务逻辑
else
业务逻辑
end if;
declare
vnum number:=#
begin
if vnum=1 then
dbms_output.put_line('登录成功');
else
dbms_output.put_line('登录失败');
end if;
end;

2.5.3 多分支

if 条件 then
业务逻辑
elsif 条件 then -- 注意:这个长相:是els+if
业务逻辑
else
业务逻辑
end if;
declare
age number:= #
begin
if age<18 then
dbms_output.put_line('未成年人');
elsif age>=18 and age<60 then
dbms_output.put_line('年轻人');
elsif age>=60 and age<80 then
dbms_output.put_line('中年人');
elsif age>=80 then
dbms_output.put_line('老人');
end if;
end;

2.5.4 Case语句

Oracle 9i之后增加的语句,笔记二未体现。

declare
age integer:=#
vresult varchar2(100); -- 别起result关键字;
begin
case
when age<18 then
vresult:='未成年人';
when age>=18 and age<60 then
vresult:='年轻人';
when age>=60 and age<80 then
vresult:='中年人';
when age>=80 then
vresult:='老年人';
end case;
dbms_output.put_line(vresult);
end;

2.6 循环

2.6.1 loop when循环

语法
loop   
--循环语句 类似于之前的do while循环
exit when 退出条件;
end loop;
演示

输出从1开始的100个数

declare
i number:=1;
begin
loop
dbms_output.put_line(i);
i:=i+1;
exit when i>100;
end loop;
end ;

2.6.2 while loop循环

语法
while 循环条件  
loop
循环体
end loop;
演示

输出从1开始的100个数

declare
i number:=1;
begin
while i<=100 loop
dbms_output.put_line(i);
i:=i+1;
end loop;
end ;

2.6.3 for .. loop循环

语法
-- for(int i=1;i<结束值;i++){}
for 变量 in 起始值..终止值 loop
-- 循环语句
end loop;
演示

输出从1开始的100个数

begin
for i in 1..100
loop
dbms_output.put_line(i);
end loop;
end;

向表中插入数据;

insert into student(id,name)values(seq_test.nextval,'李四')

-- 向student表中插入1000条数据;使用while loop循环????
declare
i number :=1;
begin
while i<=1000 loop -- 当大于2755的时候,控制台会报错;插入没问题;
-- dbms_output.put_line(i); 在sql控制台输出
insert into student(id,name)values(seq_test.nextval,'李四'||i);
commit;
i:=i+1;
end loop;
end;

三、存储函数

3.1 什么是存储函数

存储函数又称为自定义函数,一种存储在数据库中的命令程序块。可以接收零或多个参数,必须有返回值

3.2 存储函数语法

创建或修改存储过程的语法如下:

CREATE [ OR REPLACE ] FUNCTION 函数名称(参数名称 参数类型, 参数名称 参数类型,...n)
RETURN 结果变量数据类型
IS
变量声明部分;
BEGIN
-- 逻辑部分;
RETURN 结果变量;
[EXCEPTION 异常处理部分]
END;

示例

需求:根两个数相加函数

create or replace function f_sum(a number,b number) return number
is fresult number; -- 这个是变量,fresult这个是需要return
begin
fresult:=a+b;
return fresult;
end;

调用存储函数

select f_sum(3,2) from dual

小写数字转大写汉字金额 实用函数:

Create Or Replace Function Money2Chinese(Money In Number) Return Varchar2 Is
strYuan Varchar2(150);
strYuanFen Varchar2(152);
numLenYuan Number;
numLenYuanFen Number;
strRstYuan Varchar2(600);
strRstFen Varchar2(200);
strRst Varchar2(800);
Type typeTabMapping Is Table Of Varchar2(8) Index By Binary_Integer;
tabNumMapping typeTabMapping;
tabUnitMapping typeTabMapping;
numUnitIndex Number;
i Number;
j Number;
charCurrentNum Char(1);
Begin
If Money Is Null Then
Return Null;
End If;
strYuan := TO_CHAR(FLOOR(Money));
If strYuan = '0' Then
numLenYuan := 0;
strYuanFen := lpad(TO_CHAR(FLOOR(Money * 100)), 2, '0');
Else
numLenYuan := length(strYuan);
strYuanFen := TO_CHAR(FLOOR(Money * 100));
End If;
If strYuanFen = '0' Then
numLenYuanFen := 0;
Else
numLenYuanFen := length(strYuanFen);
End If;
If numLenYuan = 0 Or numLenYuanFen = 0 Then
strRst := '零圆整';
Return strRst;
End If;
tabNumMapping(0) := '零';
tabNumMapping(1) := '壹';
tabNumMapping(2) := '贰';
tabNumMapping(3) := '叁';
tabNumMapping(4) := '肆';
tabNumMapping(5) := '伍';
tabNumMapping(6) := '陆';
tabNumMapping(7) := '柒';
tabNumMapping(8) := '捌';
tabNumMapping(9) := '玖';
tabUnitMapping(-2) := '分';
tabUnitMapping(-1) := '角';
tabUnitMapping(1) := '';
tabUnitMapping(2) := '拾';
tabUnitMapping(3) := '佰';
tabUnitMapping(4) := '仟';
tabUnitMapping(5) := '万';
tabUnitMapping(6) := '拾';
tabUnitMapping(7) := '佰';
tabUnitMapping(8) := '仟';
tabUnitMapping(9) := '亿';
For i In 1 .. numLenYuan Loop
j := numLenYuan - i + 1;
numUnitIndex := Mod(i, 8);
If numUnitIndex = 0 Then
numUnitIndex := 8;
End If;
If numUnitIndex = 1 And i > 1 Then
strRstYuan := tabUnitMapping(9) || strRstYuan;
End If;
charCurrentNum := substr(strYuan, j, 1);
If charCurrentNum <> 0 Then
strRstYuan := tabNumMapping(charCurrentNum) ||
tabUnitMapping(numUnitIndex) || strRstYuan;
Else
If (i = 1 Or i = 5) Then
If substr(strYuan, j - 3, 4) <> '0000' Then
strRstYuan := tabUnitMapping(numUnitIndex) || strRstYuan;
End If;
Else
If substr(strYuan, j + 1, 1) <> '0' Then
strRstYuan := tabNumMapping(charCurrentNum) || strRstYuan;
End If;
End If;
End If;
End Loop;
For i In -2 .. -1 Loop
j := numLenYuan - i;
charCurrentNum := substr(strYuanFen, j, 1);
If charCurrentNum <> '0' Then
strRstFen := tabNumMapping(charCurrentNum) || tabUnitMapping(i) ||
strRstFen;
End If;
End Loop;
If strRstYuan Is Not Null Then
strRstYuan := strRstYuan || '圆';
End If;
If strRstFen Is Null Then
strRstYuan := strRstYuan || '整';
Elsif length(strRstFen) = 2 And substr(strRstFen, 2) = '角' Then
strRstFen := strRstFen || '整';
End If;
strRst := strRstYuan || strRstFen;
--strRst := Replace(strRst, '亿零', '亿');
--strRst := Replace(strRst, '万零', '万');
Return strRst;
End Money2Chinese;
-- 调用--
Select Money2Chinese(786.213) From dual;

四、存储过程*

4.1 什么是存储过程

存储过程是被命名的 PL/SQL 块,存储于数据库中,是数据库对象的一种。应用程序可以调用存储过程,执行相应的逻辑。存储过程与存储函数都可以封装一定的业务逻辑并返回结果,存在区别如下:

1、存储函数中有返回值,且必须返回;而存储过程没有返回值,可以通过传出参数返回多个值。
2、存储函数可以在 select 语句中直接使用,而存储过程不能。过程多数是被应用程序所调用。
3、存储函数一般都是封装一个查询结果,而存储过程一般都封装一段事务代码。

4.2 存储过程语法结构

CREATE [ OR REPLACE ] PROCEDURE   存储过程名称
(参数名 类型, 参数名 类型, 参数名 类型)
IS|AS
变量声明部分; -- 注意这里结束
BEGIN
逻辑部分
[EXCEPTION
异常处理部分]
END;

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

过程参数的三种模式:

  • ​IN​​ 传入参数(默认)
  • ​OUT​​ 传出参数 ,主要用于返回程序运行结果
  • ​IN OUT​​ 传入传出参数

4.3 案例

4.3.1 创建带输入参数的存储过程

添加部门信息

-- 创建序列
create sequence seq_dept_id start with 60 increment by 10;
-- 创建存储过程
create or replace procedure pro_dept_addinfo
(
p_dname in varchar2, -- 部门名称
p_loc in varchar2 -- 部门位置
)
is
-- 这里
begin
insert into dept values(seq_dept_id.nextval,p_dname,p_loc);
commit;
end;

PL/SQL 中调用不带传出参数的存储过程

call pro_dept_addinfo('软件测试','武汉');
or
begin
pro_dept_addinfo('软件质量','郑州');
end;
或者在命令行窗口执行
exec pro_dept_addinfo('公关部','郑州');
区别: 1.call一般用来在外部程序调用使用,例如JAVAEE;
2.begin end;一般用在在sql窗口执行;
3.exec 在命令行窗口使用;

4.3.2 创建带传出参数的存储过程

输入参数是in,输出参数是out

格式:

参数名 out 类型

一般用来创建比较灵活输出的存储过程实用场景;

Create or replace procedure getRax(xsal in number,fee out number)
as
r number:=xsal-5000;
begin
case
when r<0 then fee:=0;
when r<=3000 then fee:=r*0.03;
when r<=12000 then fee:=r*0.1-210;
when r<=25000 then fee:=r*0.2-1410;
when r<=35000 then fee:=r*0.25-2660;
when r<=55000 then fee:=r*0.3-4410;
when r<=80000 then fee:=r*0.35-7160;
else
fee:=r*0.45-15160;
end case;
end;

PL/SQL 中调用传出参数的存储过程

对于有数据返回的,在PL/SQL中只能使用begin end,不能使用call方式

-- 调用传出参数存储过程
declare
fee number;
begin
getRax(&xsal,fee);
dbms_output.put_line('应交税额:'||fee);
end;

如果是命令窗口就用exec 存储过程名,举个栗子:

1.如果是命令窗口就用exec 存储过程名,举个栗子:

EXEC` `procedure ``;``--procedure是存储过程名

2.如果是PL/SQL窗口就用 begin 存储过程名 end; 举个栗子:

begin
``procedure``;``--procedure是存储过程名
end``;

3.如果是程序中调用就用 call 存储过程名 ,举个栗子:

hibernateDao.excuteSqlUpdate("{Call proc_stuInfo()}");//存储过程proc_stuInfo

五、JDBC连接Oracle

5.1 创建工程,导入jar包

5.2 编写JDBC工具类

properties配置文件
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
username=oracletest
password=root
JDBCUtil
public class JDBCUtil {
private static String driver;
private static String url;
private static String username;
private static String password;
private static Connection conn;

static {
try {
// 读取加载配置文件
InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties pro = new Properties();
pro.load(is);

driver = pro.getProperty("driver");
url = pro.getProperty("url");
username = pro.getProperty("username");
password = pro.getProperty("password");

// 加载驱动
Class.forName(driver);
// 连接oracle

} catch (Exception e) {
e.printStackTrace();
}
}
// 获取数据库连接
public static Connection getConnection() {
conn = DriverManager.getConnection(url, username, password);
return conn;
}
/**
* 关闭资源
*
* @param rs
* @param stmt
* @param conn
*/
public static void close(ResultSet rs, Statement stmt, Connection conn) {
//关闭结果集
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//关闭执行对象
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//关闭执行对象
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

5.3 JDBC工具类测试

public class JDBCTest {
public static void main(String[] args) {
Connection conn = JDBCUtil.getConnection();
System.out.println(conn);
}
}

六、Oracle增删改查

以dept表为例,演示增删改查

6.1 编写实体类

public class Dept {
private Integer id;
private String dname;
private String loc;
// 省略有参和无参 getter和setter toString
}

6.2 DeptDao

public class DeptDao {
public void addDept(Dept dept) throws SQLException {
Connection conn = JDBCUtil.getConnection();

String sql = "insert into dept (id,dname,loc) values (?,?,?)";
PreparedStatement pstmt = conn.prepareStatement(sql);

pstmt.setInt(1, dept.getId());
pstmt.setString(2,dept.getDname());
pstmt.setString(3,dept.getLoc());

pstmt.execute();

JDBCUtil.close(null,pstmt,conn);
}
}

6.3 DeptTest

public class DeptTest {
public static void main(String[] args) throws SQLException {
DeptDao dao = new DeptDao();
Dept dept = new Dept(80,"总裁委员会","北京");
dao.addDept(dept);
}
}

七、数据导出与导入

当我们使用一个数据库时,总希望数据库的内容是可靠的、正确的,但由于计算机系统的故障(硬件故障、软件故障、网络故障、进程故障和系统故障)影响数据库系统的操作,影响数据库中数据的正确性,甚至破坏数据库,使数据库中全部或部分数据丢失。因此当发生上述故障后,希望能重构这个完整的数据库该处理称为数据库恢复,而要进行数据库的恢复必须要有数据库的备份工作。

7.1 整库导出与导入

整库导出命令
exp 用户名/密码@实例名 file=导出的dmp文件存放路径 log=导出日志存放路径
添加参数 full=y 就是整库导出

执行命令后会在当前目录下生成一个叫 EXPDAT.DMP,此文件为备份文件。

如果想指定备份文件的名称,则添加 file 参数即可,命令如下

exp 用户名/密码@实例名 file=文件名 full=y

案例:将u1用户下导出到d盘中,文件叫做u1.dmp

exp u1/123456 file='u1.dmp'
整库导入命令
imp 用户名/密码 file='文件'

案例:

imp u1/123456 file='u1.dmp'

7.2 按用户导出与导入

按用户导出
exp system/oracletest owner=oracletest file=oracletest.dmp
按用户导入
imp system/oracletest file=oracletest.dmp fromuser=oracletest

7.3 按表导出与导入

按表导出
exp oracletest/root file=a.dmp tables=dept
用 tables 参数指定需要导出的表,如果有多个表用逗号分割即可
按表导入
imp oracletest/root file=a.dmp tables=dept

标签:存储,end,--,begin,put,SQL,Oracle,PL,dbms
From: https://blog.51cto.com/teayear/5776760

相关文章

  • JMeter 扩展开发:自定义 Java Sampler
    JMeter内置支持了一系列的常用协议,例如HTTP/HTTPS、FTP、JDBC、JMS、SOAP和TCP等,可以直接通过编写脚本来支持相关协议的测试场景。除了这些协议之外,用户也可能需要进行......
  • 奇迹客户端服务端目录PLAYER文件怎么改​
    奇迹客户端服务端目录PLAYER文件怎么改​我是艾西,很多想开服的小伙伴对游戏技术肯定是感兴趣的,今天跟大家聊聊Player目录文件代表什么意思怎么修改:​这一期就是大家很关心的......
  • oracle 表空间不够处理
    1、查询表空间情况:selectb.file_id文件ID,b.tablespace_name表空间,b.file_name物理文件名,b.bytes总字节数,(b.......
  • mysql系列-常用语句
    一查看空间碎片-库维度   selecttable_schemaas'数据库',sum(table_rows)as'记录数',sum(truncate(data_length/1024/1024/1024,2))as'数据容量(GB)'......
  • MySQL-explain
    转自:https://www.cnblogs.com/ciel717/p/16180093.html通常查询慢查询SQL语句时会使用EXPLAIN命令来查看SQL语句的执行计划,通过返回的信息,可以了解到Mysql优化器是如何执......
  • greenplum角色权限及客户端认证管理
    一、gp数据库逻辑结构  在GP中,Database(数据库)、Schema(模式)以及Role(角色)三者之间的关系如下: 1、一个数据库下可以有多个模式,一个模式只属于一个数据库。模式在GP中......
  • Mysql 身份认证绕过漏洞(CVE-2012-2122)
    参考文章:http://t.csdn.cn/CJuGe搭建环境https://vulhub.org/#/environments/mysql/CVE-2012-2122/主机准备准备两台主机,一台ubuntu(192.168.12.137),一台kail,均处于......
  • MySQL5.7二进制安装
    1、上传安装包到服务器,并解压tarzxvfmysql-5.7.33-linux-glibc2.12-x86_64.tar.gz-C/usr/local/mv/usr/local/mysql-5.7.33-linux-glibc2.12-x86_64/usr/local/my......
  • MASA MAUI Plugin (四)条形码、二维码扫描功能
    背景MAUI的出现,赋予了广大.Net开发者开发多平台应用的能力,MAUI是Xamarin.Forms演变而来,但是相比Xamarin性能更好,可扩展性更强,结构更简单。但是MAUI对于平台相关的实现并......
  • greenplum架构
    一、并行和分布式1、海量并行处理(DBMS)2、基于pg8.2 (1)相同的客户端功能。 (2)增加支持并行处理的技术。 (3)增加支持数据仓库和BI的特性:外部表/并行加载   ......