1 PL/SQL

1.1什么是PL/SQL?

n  PL:Process Language

n  PL/SQL是oracle对sql语言的过程化扩展

n  在SQL语言中添加了过程处理语句(如分支,循环),使SQL语言具有过程处理能力

1.2 PL/SQL程序结构

Declare

说明部分 (变量、光标、例外声明)

Begin

语句序列(DML)...

Exception

例外处理语句

End;

1.3变量声明

n  可以声明的变量类型 char,varchar2,boolean,date,number,long

--查找7839的员工信息

--打开输出

set serveroutput on

declare

pename emp.ename%type;--名字变量

psal emp.sal%type;--薪水变量

begin

select ename,sal into pename,psal from emp where empno=7839;

--输出

DBMS_OUTPUT.PUT_LINE(pename||'的薪水是'||psal);

end;

1.4 if语句

--判断用户从键盘输入的数字

--打开输出

set serveroutput on

--num是地址值,用来保存输入的值

accept num prompt '请输入一个数字'

declare

pnum number :=#

begin

if pnum = 0 then dbms_output.put_line('你输入的是0');

elsif pnum = 1 then dbms_output.put_line('你输入的是1');

elsif pnum = 2 then dbms_output.put_line('你输入的是2');

else dbms_output.put_line('其它数字');

end if;

end;

1.5循环

--打开输出

set serveroutput on

declare

pnum number :=1;

begin

loop

exit when pnum > 10;

dbms_output.put_line(pnum);

pnum :=pnum + 1;

end loop;

end;

1.6光标

n  光标(cursor)也被称为游标。Oracle 使用两种光标:显示光标和隐式光标。

n  不管语句返回多少条纪录, PL/SQL 为使用的每一条 UPDATE 、 DELETE 和 INSERT 等 SQL 命令隐式的声明一个光标。

光标的作用

n  当 PL/SQL 光标查询返回多行数据时,这些记录组被称为活动集。 Oracle 将这种活动集存储在您创建的显示定义的已命名的光标中。Oracle 光标是一种用于轻松的处理多行数据的机制,没有光标, Oracle 开发人员必须单独地、显示地取回并管理光标查询选择的每一条记录。

n  光标的另一项功能事,它包含一个跟踪当前访问的记录的指针,这使您的程序能够一次处理多条记录。

练习

遍历员工薪水

set serveroutput on

declare

cursor cemp is select ename,sal from emp;

pename emp.ename%type;

psal emp.sal%type;

begin

--打开光标

open cemp;

loop

fetch cemp into pename,psal;

exit when cemp%notfound;

dbms_output.put_line(pename||'的薪水是'||psal);

end loop;

--关闭光标

close cemp;

end;

涨工资,总裁1000 经理800 其他400

set serveroutput on

declare

--job在plsql中是一个关键字,重命名一下

--alter table "SCOTT"."EMP" rename column "JOB" to empjob

cursor cemp is select empno,empjob from emp;

pempno emp.empno%type;

pjob emp.empjob%type;

begin

--rollback;

--打开光标

open cemp;

loop

fetch cemp into pempno,pjob;

exit when cemp%notfound;

if pjob='PRESIDENT' then update emp set sal = sal + 1000 where empno=pempno;

elsif pjob='MANAGER' then update emp set sal = sal + 800 where empno=pempno;

else  update emp set sal = sal + 400 where empno=pempno;

end if;

end loop;

--关闭光标

close cemp;

--需要提交

commit;

end;

带参数的光标

set serveroutput on

declare

cursor cemp(dNo number) is select ename,sal from emp where deptno = dNo;

pename emp.ename%type;

psal emp.sal%type;

begin

--打开光标

open cemp(20);

loop

fetch cemp into pename,psal;

exit when cemp%notfound;

dbms_output.put_line(pename||'的薪水是'||psal);

end loop;

--关闭光标

close cemp;

end;

n  默认,一个会话中只能打开300个光标

SQL> show parameter cursor【只能系统管理员可查看】

SQL>alter system set open_cursors=400; 【修改】

1.7例外(异常)

n  例外是程序设计语言提供的一种功能,用来增强程序的键壮性和容错性

n  oracle的异常处理

n  系统定义的例外【异常】

n  No_data_found【没有找到数据】

n  Too_many_row【select ...into语句匹配多个行】

n  Zero_Divide【被零除】

n  Value_error 【算术或转换错误】

n  Timeout_on_resource【在等待资源时发生超时】

系统异常

set serveroutput on

declare

pnum number;

begin

pnum:=1/0;

--pnum:='b';

exception

when zero_divide then DBMS_OUTPUT.PUT_LINE('0不能做分母');

DBMS_OUTPUT.PUT_LINE('0不能做分母');--可写多行

when value_error then  DBMS_OUTPUT.PUT_LINE('算术转换异常');

when others then  DBMS_OUTPUT.PUT_LINE('其它导常');

end;

自定义异常

--查询50号部门的员工姓名

set serveroutput on

declare

cursor cemp is select ename from emp where deptno=50;

pename emp.ename%type;

--自定义异常

no_emp_found exception;

begin

open cemp;

--取第一条记录

fetch cemp into pename;

if cemp%notfound then

--抛出异常

raise no_emp_found;

end if;

close cemp;

exception

when no_emp_found then dbms_output.put_line('没有找到员工');

when others then dbms_output.put_line('其他例外');

end;

1.8案例

n  统计每年入职的员工数

set serveroutput on

declare

cursor cemp is select to_char(hiredate,'yyyy') from emp;

phiredate varchar2(4);

--声明变量

count80 number :=0;

count81 number :=0;

count82 number :=0;

count87 number :=0;

begin

open cemp;

loop

 fetch cemp into phiredate;

    exit when cemp%notfound;

if phiredate = '1980' then count80:=count80+1;

elsif phiredate = '1981' then count81:=count81+1;

elsif phiredate = '1982' then count82:=count82+1;

else count87:=count87+1;

end if;

end loop;

close cemp;

DBMS_OUTPUT.PUT_LINE('Total'||(count80 + count81 + count82 + count87));

DBMS_OUTPUT.PUT_LINE('1980'||count80);

DBMS_OUTPUT.PUT_LINE('1981'||count81);

DBMS_OUTPUT.PUT_LINE('1982'||count82);

DBMS_OUTPUT.PUT_LINE('1987'||count87);

end;

n

1.9案例

n  为员工涨工资。从最低工资起,每人涨10%,但总额不能超过5W,请计算涨工资的人数和长工资后的工资总额

/**

1.为员工涨工资。从最低工资起,每人涨10%,

2.但总额不能超过5W,请计算涨工资的人数和长工资后的工资总额

1.声明变量

涨工资的人数 countEmp number:0;

涨工资的总额 salTotal number;

[select sum(sal) into salTotal from emp];

2.得到初始的工资总和

3.光标遍历

4.如果总额大于5000就不加工资

*/

set serveroutput on

declare

cursor cemp is select empno,sal from emp order by sal;

pempno emp.empno%type;

psal emp.sal%type;

countEmp number:=0;--涨工资的人数

salTotal number;--工资的总额

begin

--获取当前总工资

select sum(sal) into salTotal from emp;

open cemp;

loop

--大于5W不在加工资

exit when salTotal > 50000;

fetch cemp into pempno,psal;

--没有光标,无下条记录

exit when cemp%notfound;

--涨工资

update emp set sal = sal*1.1 where empno=pempno;

--涨工资人数

countEmp :=countEmp+1;

--涨后金额

salTotal :=salTotal + psal*0.1;

end loop;

close cemp;

commit;--提交事务

DBMS_OUTPUT.PUT_LINE('涨工资人数'||countEmp);

DBMS_OUTPUT.PUT_LINE('涨后工资总额'||salTotal);

end;

2.0案例

n  实现按部门分段(6000以上),(6000,3000),3000元以下统计各工资段的职工人数,以及各部门的工资总和

 

/*

1.部门 遍历打印部门编号

2.部门员工遍历,薪水

3.声明三个区间的变量

4.声明部门总工资变量

*/

set serveroutput on

declare

--部门光标

cursor cdept is select deptno from dept;

--部门ID变量

pdeptno dept.deptno%type;

--员工光标

cursor cemp(dNo number) is select sal from emp where deptno=dNo;

psal emp.sal%type;

--每个区间的员工个数

count1 number;-->6000

count2 number;--<3000

count3 number;--3000~600

totalSal number;--部门上总工资

begin

--打开光标

open cdept;

--1.遍历部门

loop

count1:=0;count2:=0;count3:=0;

fetch cdept into pdeptno;

exit when cdept%notfound;

select sum(sal) into totalSal from emp where deptno = pdeptno;

--打印部门编号

DBMS_OUTPUT.PUT_LINE ('部门编号'||pdeptno ||'总工资'||nvl(totalSal,0));

--2.根据部门编号遍历员工

open cemp(pdeptno);

loop

fetch cemp into psal;

exit when cemp%notfound;

--打印工资

--DBMS_OUTPUT.PUT_LINE ('--'||psal);

--3.遍历员工工资区间

if psal>6000 then count1 :=count1+1;

elsif psal<3000 then count2 :=count2+1;

else count3 :=count3+1;

end if;

end loop;

close cemp;

--打印工资区间人数

DBMS_OUTPUT.PUT_LINE ('工资>6000:'||count1||' 工资<3000:'||count2||' 工资3000~6000:'||count3);

DBMS_OUTPUT.PUT_LINE ('=========================================');

--结束循环

end loop;

--关闭光标

close cdept;

end;

2 存储过程,函数

2.1存储过程和存储函数

n  指存储在数据库中供所有用户程序调用的子程序叫存储过程和存储函数

2.2创建存储过程语法

Create [or replace] procedure 过程名(参数)

as

PLSQL子程序

无参数的存储过程

--创建一个存储过程

create or replace procedure sayHelloWord

as

--说明部份

begin

DBMS_OUTPUT.PUT_LINE('Hello Word');

end;

--调用存储过程 第一方式

EXECUTE sayHelloWord();

--调用存储过程 第二方式

begin

sayHelloWord();

sayHelloWord();

end;

带参数的存储过程

--给指定的员工涨工资100,并且涨前涨后的薪水

create or replace procedure raisesalary(eno in number)

as

psal emp.sal%type;

begin

--得到当前薪水

select sal into psal from emp where empno = eno;

--涨100

update emp set sal=sal+100 where empno=eno;

--打印

DBMS_OUTPUT.put_line('涨前:'||psal||' 涨后:'||(psal + 100));

end;

--调用存储过程

set serveroutput on

begin

raisesalary(7369);

raisesalary(7369);

--需要在这里提交事务,不要在内部提交

commit;

end;

2.3存储过程的调试

n  如图,存储过程可调试,但在调试前需要给于权限

n  然后加断点调试,先选择调用,用法跟java的调试差不多

 

授权

 

2.4存储函数

n  函数(Function)为一命名的存储函数,可以带参数,并返回一计算值。函数和过程的结构相似,但必需要有一个return语句,用于返回函数值。函数说明要指定函数名、结果值的类型,以及参数类型。

2.5创建存储函数语法

Create [or replace] function 函数名(参数)return 返回值类型

as

PLSQL子程序

函数声明 【计算年薪】

create or replace function queryincome(eno in number) return number

as

psal emp.sal%type;--月薪

pcomm emp.comm%type;--奖金

begin

--得到当前月薪和奖金

select sal,comm into psal,pcomm from emp where empno = eno;

--返回年收入

return psal*12 + nvl(pcomm,0);

end;

函数调用

set serveroutput on

--函数的调用

declare

y_sal number;

begin

y_sal:=queryincome(7369);

DBMS_OUTPUT.put_line('年薪:'||y_sal);

end;

2.6 什么时候用存储函数和存储过程

n  如果有一个返回值就用存储函数,否则就用存储过程

3 java中调用存储过程和函数

创建一个存储过程【根据员工编号返回员工名字和工资】

create or replace procedure queryempinfo(eno in number,empname out varchar,empsal out number)

as

psal emp.sal%type;

begin

select ename,sal into empname,empsal from emp where empno = eno;

end;

创建一个java项目,导入ojdbc和junit

写一个JDBC工具包

package demo;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.sql.Statement;

public class JDBCUtils {

private static String driver = "oracle.jdbc.OracleDriver";

private static String url = "jdbc:oracle:thin:@192.168.56.102:1521:orcl";

private static String user = "scott";

private static String password = "scott";

static{

try {

Class.forName(driver);

} catch (ClassNotFoundException e) {

// TODO: handle exception

e.printStackTrace();

}

}

/**

* 返回一个数据连接

* */

public static Connection getConnection(){

try {

return DriverManager.getConnection(url, user, password);

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return null;

}

public static void rlease(Connection conn,Statement st,ResultSet rs){

if(rs!=null){

try {

rs.close();

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally{

rs = null;//释放

}

}

if(st != null){

try {

st.close();

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally{

st = null;//释放

}

}

if(conn != null){

try {

conn.close();

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally{

conn = null;//释放

}

}

}

}

存储过程的调用

@Test

public void testProcedure(){

//存储过程的java写法{call <procedure-name>[(<arg1>,<arg2>, ...)]}

String p = "{call queryempinfo(?,?,?)}";

Connection con =null;

CallableStatement call = null;

try {

con = JDBCUtils.getConnection();

call = con.prepareCall(p);

//对于in参数,赋值

call.setInt(1, 7369);

//设置out参数类型

call.registerOutParameter(2, OracleTypes.VARCHAR);

call.registerOutParameter(3, OracleTypes.NUMBER);

//执行

call.execute();

//取结果

String ename = call.getString(2);

double sal = call.getDouble(3);

System.out.println(ename);

System.out.println(sal);

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally {

JDBCUtils.rlease(con, call, null);

}

}

存储函数的调用{?=call <funtion-name>[(<arg1>,<arg2>, ...)]}

@Test

public void testFunction(){

//存储方法的java写法{?=call <funtion-name>[(<arg1>,<arg2>, ...)]}

String p = "{?=call queryincome(?)}";

Connection con =null;

CallableStatement call = null;

try {

con = JDBCUtils.getConnection();

call = con.prepareCall(p);

//对于in参数,赋值

call.setInt(2, 7369);

//设置out参数类型

call.registerOutParameter(1, OracleTypes.NUMBER);

//执行

call.execute();

//取结果

double y_sal = call.getDouble(1);

System.out.println(y_sal);

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally {

JDBCUtils.rlease(con, call, null);

}

}

4 触发器

4.1触发器定义

n  数据库触发器是一个与表相关联、存储的PL/SQL程序。每当一个特定的数据操作语句(Insert,Update,delete)在指定的表上发出时,Oracle自动地执行触发器中定义的语句序列。

n  触发器的类型

n  语句级触发器

u  在指定的操作语句操作之前或之后执行一次,不管这条语句影响了多少行。

n  行级触发器(FOR EACH ROW)

n  触发语句作用的每一条记录都被触发。在行级触发器使用:old和:new 伪记录变量,识别值的状态

4.2触发器语法格式

CREATE [or REPLACE] TRIGGER 触发器名

{BEFORE | ALTER}

{DELETE | INSERT | UPDATE [OF 列名]}

ON 表名

[FOR EACH ROW [WHEN(条件)]]

PLSQL 块

4.3案例

第一个触发器,插入员工后打印一句输出

create trigger abcd after insert on emp

declare

begin

DBMS_OUTPUT.PUT_LINE('成功插入新员工');

end;

set serveroutput on

insert into emp (empno,ename,sal,deptno) values(1122,'zhangsan',1920,10);

2.实施复杂的安全性检查 禁止在非工作时间插入新员工

create trigger securityemp before insert on emp

begin

if to_char(sysdate,'day') in ('星期六','星期日') or

to_number(to_char(sysdate,'hh24')) not between 9 and 17

then RAISE_APPLICATION_ERROR(-20001, '禁止非工作时间插入新员工');

end if;

end;

set serveroutput on

insert into emp (empno,ename,sal,deptno) values(1432,'zhangsan3',1920,10);

commit;

3涨后的工资不能少于涨前的工资

create or replace trigger checksalary

before update

on emp

for each row

begin

if :new.sal < :old.sal  then

raise_application_error(-20002,'涨后的工资不能少于涨前的工资new:'||:new.sal||' old:'||:old.sal);

end if;

end;

set serveroutput on;

update emp set sal = sal -10 where empno=1122;

Oracle-PL/SQL语句的更多相关文章

  1. Oracle——PL/SQL 语句

    目录: 1.什么是PL/SQL  2.PL/SQL 语法基础 3.PL/SQL 实例 一.过程 实例   二.函数 实例   三.游标的使用 实例 四.动态sql 实例 五.触发器 实例  1.什么是 ...

  2. Oracle PL/SQL语句基础学习笔记(上)

    PL/SQL是ORACLE对标准数据库语言的扩展,ORACLE公司已经将PL/SQL整合到ORACLE server和其它工具中了,近几年中很多其它的开发者和DBA開始使用PL/SQL,本文将讲述PL ...

  3. Oracle PL/SQL

    PL/SQL 简介 PL/SQL 是过程语言(Procedural Language)与结构化查询语言(SQL)结合而成的编程语言,是对 SQL 的扩展,它支持多种数据类型,如大对象和集合类型,可使用 ...

  4. ORACLE PL/SQL编程详解

    ORACLE PL/SQL编程详解 编程详解 SQL语言只是访问.操作数据库的语言,并不是一种具有流程控制的程序设计语言,而只有程序设计语言才能用于应用软件的开发.PL /SQL是一种高级数据库程序设 ...

  5. oracle常用SQL语句(汇总版)

    Oracle数据库常用sql语句 ORACLE 常用的SQL语法和数据对象一.数据控制语句 (DML) 部分 1.INSERT (往数据表里插入记录的语句) INSERT INTO 表名(字段名1, ...

  6. [强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!)

    原文:[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!) [强烈推荐]ORACLE PL/SQL编程详解之七: 程序包的创建与应用(聪明在于学习,天 ...

  7. ORACLE PL/SQL编程之八:把触发器说透

    原文:ORACLE PL/SQL编程之八:把触发器说透 ORACLE PL/SQL编程之八: 把触发器说透 大家一定要评论呀,感谢!光发表就花了我将近一个下午. 本篇主要内容如下: 8.1 触发器类型 ...

  8. [推荐]ORACLE PL/SQL编程之五:异常错误处理(知已知彼、百战不殆)

    原文:[推荐]ORACLE PL/SQL编程之五:异常错误处理(知已知彼.百战不殆) [推荐]ORACLE PL/SQL编程之五: 异常错误处理(知已知彼.百战不殆) 继上三篇:ORACLE PL/S ...

  9. ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!)

    原文:ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!) ORACLE PL/SQL编程之六: 把过程与函数说透(穷追猛打,把根儿都拔起!)   继上篇:ORACLE P ...

  10. [推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆)

    原文:[推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆) [推荐]ORACLE PL/SQL编程详解之三: PL/SQL流程控制语句(不给规则,不成方圆) ...

随机推荐

  1. Python笔记_第五篇_Python数据分析基础教程_文件的读写

    1. 读写文件(基本) savetxt.loadtxt i2 = np.eye(2) print(i2) np.savetxt(r"C:\Users\Thomas\Desktop\eye.t ...

  2. windows 10下的python开发环境

    linux子系统 按照文档 https://www.jianshu.com/p/2bcf5eca5fbc 的前五步,完成 ubuntu子系统安装. 不需安装图形桌面,无使用价值. 在https://w ...

  3. Thread--线程工作万花筒

    线程工作内存图. 线程状态.

  4. JXCPC 试题册

    JXCPC 试题册 Input file: standard input Output file: standard output Time limit: 1s Memory limit: 256 m ...

  5. JVM探秘:jmap生成内存堆转储快照

    本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. jmap 命令用来生成内存堆转储快照,一般称为heapdump或dump文件. 除了使 ...

  6. .NET 请求认证之access-token(oauth2.0与owin的结合)

    公司对外开放的接口,大多需要请求认证,如微信,阿里等.最近我刚好在搭建webapi框架.记录一下自己的理解. 一:请求认证的目的   之所以要对我们的接口进行请求认证,就是为了安全考虑的.以前都是在用 ...

  7. Mybatis学习——Mybatis核心配置

    MyBatis的核心配置 在使用MyBatis框架时,设计两个核心的d对象:SqlSessionFactory和SqlSession. SqlsessionFactory SqlSessionFact ...

  8. PAT Advanced 1070 Mooncake (25) [贪⼼算法]

    题目 Mooncake is a Chinese bakery product traditionally eaten during the Mid-Autumn Festival. Many typ ...

  9. C++常用库函数 C函数库 cstdio

    常用的C/C++函数库, cstdio(stdio.h) 标准输入输出库.C Standard Input and Output Library 1. 实例 #include <cstdio&g ...

  10. 自由职业平台Upwork申请上市,能给国内猪八戒网带来什么启示?

    当下,在互联网的全面渗入下已经对整个社会的运行机制.大众的生活产生了前所未有的影响.尤其是在工作方面,更是衍生出诸多新兴职业.如,主播.水军.新媒体运营.自媒体人等.值得注意的是,这些职业绝大部分都有 ...