oracle从入门到精通复习笔记续集之PL/SQL(轻量版)
复习内容:
PL/SQL的基本语法、记录类型、流程控制、游标的使用、
异常处理机制、存储函数/存储过程、触发器。
为方便大家跟着我的笔记练习,为此提供数据库表文件给大家下载:点我下载
为了要有输出的结果,在写PL/SQL程序前都在先运行这一句:
set serveroutput on
结构:
declare
--声明变量、类型、游标
begin
--程序的执行部分(类似于java里的main()方法)
exception
--针对begin块中出现的异常,提供处理的机制
--when...then...
--when...then...
end;
举例1:
declare
v_sal number(10); (注意每句话后面别忘记了分号,跟java中的一样)
begin
select salary into v_sal from employees where employee_id = 100;
dbms_output.put_line(v_sal);
end;
举例2:
declare
v_sal number(10); (注意,这里声明的空间大小不能比原表中的小)
v_email varchar2(20);
v_hire_date date;
begin
select salary,email,hire_date into v_sal,v_email,v_hire_date from employees where employee_id =
100;
dbms_output.put_line(v_sal||','||v_email||','||v_hire_date);
end;
或者:
declare
v_sal employees.salary%type;
v_email employees.email%type;
v_hire_date employees.hire_date%type;
begin
select salary,email,hire_date into v_sal,v_email,v_hire_date from employees where employee_id =
100;
dbms_output.put_line(v_sal||','||v_email||','||v_hire_date);
end;
记录:
declare
type emp_record is record(
v_sal employees.salary%type,
v_email employees.email%type,
v_hire_date employees.hire_date%type
);
v_emp_record emp_record;
begin
select salary,email,hire_date into v_emp_record from employees where employee_id = 100;
dbms_output.put_line(v_emp_record.v_sal||','||v_emp_record.v_email||','||
v_emp_record.v_hire_date);
end;
1、pl/sql基本的语法格式
2、记录类型 type ... is ...record(,,,);
3、流程控制:
3.1 条件判断(两种)
方式一: if ... then elseif then ... else ... end if;
方式二: case ... when ... then ...end;
3.2 循环结构(三种)
方式一:loop ... exit when ... end loop;
方式二:while ... loop ... end loop;
方式三:for i in ... loop ... end loop;
3.3 goto、exit
4.游标的使用(类似于java中的Iterator)
5.异常的处理
6.会写一个存储函数(有返回值)、存储过程(没有返回值)
7.会写一个触发器
复习记录类型:
declare
type emp_record is record(
-- v_emp_id employees.employee_id%type,
-- v_sal employees.salary%type
v_emp_id number(10) := 120,
v_sal number(10,2) :=12000
);
v_emp_record emp_record;
begin
-- select employee_id,salary into v_emp_record from employees where employee_id = 123;
dbms_output.put_line('employee_id:'||v_emp_record.v_emp_id||' '||'salary:'||
v_emp_record.v_sal);
end;
也可以升级一下,要是想对表的所有列都输出,则:(须注意输出的列名要跟表中的列名要一样)
declare
v_emp_record employees%rowtype;
begin
select * into v_emp_record from employees where employee_id = 123;
dbms_output.put_line('employee_id:'||v_emp_record.employee_id||' '||'salary:'||
v_emp_record.salary);
end;
使用记录来执行update操作:
declare
v_emp_id number(10);
begin
v_emp_id :=123;
update employees
set salary = salary + 100
where employee_id = v_emp_id;
dbms_output.put_line('执行成功!~~');
end;
流程控制:
查询150号员工的工资,若其工资大于或等于10000 则打印‘salary >= 10000’;
若在5000到10000之间,则打印‘5000 <= salary <10000’;否则打印‘salary < 5000’
declare
v_sal employees.salary%type;
begin
select salary into v_sal from employees where employee_id =150;
if v_sal >= 10000 then dbms_output.put_line('salary >= 10000');
elsif v_sal > 5000 then dbms_output.put_line('10000 > salary >= 5000');
else dbms_output.put_line('salary < 5000');
end if;
dbms_output.put_line('salary:'||v_sal);
end;
利用case ... when ... then ... when ...then ... else ... end实现上题;
declare
v_sal employees.salary%type;
v_temp varchar2(20);
begin
select salary into v_sal from employees where employee_id =150;
v_temp :=
case trunc(v_sal/5000) when 0 then 'salary < 5000'
when 1 then '5000 <= salary < 10000'
else 'salary >= 10000'
end;
dbms_output.put_line('salary:'||v_sal||' '||v_temp);
end;
查询出122号员工的job_id,若其值为 ‘IT_PROG’, 则打印‘GRADE:A’
‘AC_MGT’, 则打印‘GRADE:B’
‘AC_ACCOUNT’, 则打印‘GRADE:B’
否则打印‘GRADE:D’
declare
v_job_id employees.job_id%type;
v_temp varchar2(20);
begin
select job_id into v_job_id from employees where employee_id =122;
v_temp :=
case v_job_id when 'IT_PROG' then 'A'
when 'AC_MGT' then 'B'
when 'AC_ACCOUNT' then 'C'
else 'D'
end;
dbms_output.put_line('job_id:'||v_job_id||' '||v_temp);
end;
使用循环语句打印:1-100
declare
v_i number(5) :=1;
begin
loop
dbms_output.put_line(v_i);
exit when v_i >=100;
v_i := v_i + 1;
end loop;
end;
使用while实现:
declare
v_i number(5) :=1;
begin
while v_i <= 100 loop
dbms_output.put_line(v_i);
v_i := v_i + 1;
end loop;
end;
使用for...in...loop...end loop;实现:
begin
for c in 1..100 loop
dbms_output.put_line(c);
end loop;
end;
输出2-100之间的质数
declare
v_i number(3):= 2;
v_j number(3):= 2;
v_flag number(1):= 1;
begin
while v_i<=100 loop
while v_j<=sqrt(v_i) loop
if mod(v_i,v_j)=0 then v_flag:=0;
end if;
v_j:= v_j+1;
end loop;
if v_flag = 1 then dbms_output.put_line(v_i);
end if;
v_j :=2;
v_i := v_i + 1;
v_flag := 1;
end loop;
end;
利用for循环实现输出2-100之间的质数:
declare
v_flag number(1):= 1;
begin
for v_i in 2..100 loop
for v_j in 2..sqrt(v_i) loop
if mod(v_i,v_j)=0 then v_flag:=0;
end if;
end loop;
if v_flag=1 then dbms_output.put_line(v_i);
end if;
v_flag := 1;
end loop;
end;
可以用goto改进一下:
declare
v_flag number(1):= 1;
begin
for v_i in 2..100 loop
for v_j in 2..sqrt(v_i) loop
if mod(v_i,v_j)=0 then v_flag:=0;
goto label;
end if;
end loop;
<<label>>
if v_flag=1 then dbms_output.put_line(v_i);
end if;
v_flag := 1;
end loop;
end;
打印1-100的自然数,当打印到50时,跳出循环 ,输出‘打印结束’:
begin
for i in 1..100 loop
if i=50 then goto label;
end if;
dbms_output.put_line(i);
end loop;
<<label>>
dbms_output.put_line('打印结束');
end;
或者:
begin
for i in 1..100 loop
if i=50 then dbms_output.put_line('打印结束');
exit;
end if;
dbms_output.put_line(i);
end loop;
end;
游标:
打印出80部门的所有的员工的工资:salary:XXX
declare
v_sal employees.salary%type;
--定义游标
cursor emp_sal_cursor is select salary from employees where department_id = 80;
begin
--打开游标
open emp_sal_cursor;
--提取游标
fetch emp_sal_cursor into v_sal;
while emp_sal_cursor%found loop
dbms_output.put_line('salary:'||v_sal);
fetch emp_sal_cursor into v_sal;
end loop;
--关闭游标
close emp_sal_cursor;
end;
可以进行优化如下:
declare
v_empid employees.employee_id%type;
v_lastName employees.last_name%type;
v_sal employees.salary%type;
cursor emp_sal_cursor is select employee_id,last_name,salary from employees where
department_id = 80;
begin
open emp_sal_cursor;
fetch emp_sal_cursor into v_empid,v_lastName,v_sal;
while emp_sal_cursor%found loop
dbms_output.put_line('employee_id:'||v_empid||', '||'last_name:'||v_lastName||',
'||'salary:'||v_sal);
fetch emp_sal_cursor into v_empid,v_lastName,v_sal;
end loop;
close emp_sal_cursor;
end;
或者使用记录再优化一下:
declare
type emp_record is record(
v_empid employees.employee_id%type,
v_lastName employees.last_name%type,
v_sal employees.salary%type
);
v_emp_record emp_record;
cursor emp_sal_cursor is select employee_id,last_name,salary from employees where
department_id = 80;
begin
open emp_sal_cursor;
fetch emp_sal_cursor into v_emp_record;
while emp_sal_cursor%found loop
dbms_output.put_line('employee_id:'||v_emp_record.v_empid||', '||'last_name:'||
v_emp_record.v_lastName||', '||'salary:'||v_emp_record.v_sal);
fetch emp_sal_cursor into v_emp_record;
end loop;
close emp_sal_cursor;
end;
可以使用for循环最优化:(注意:在for循环中它会自动的打开游标、提取游标,当提取完里面的数据后也会自动
的关闭游标)
declare
cursor emp_sal_cursor is select employee_id,last_name,salary from employees where
department_id = 80;
begin
for c in emp_sal_cursor loop
dbms_output.put_line('employee_id:'||c.employee_id||', '||'last_name:'||c.last_name||',
'||'salary:'||c.salary);
end loop;
end;
利用游标,调整公司中员工的工资:
工资范围 调整基数
0 - 5000 5%
5000 - 10000 3%
10000 - 15000 2%
15000 - 1%
实现:
declare
cursor emp_cursor is select employee_id,salary from employees;
v_empid employees.employee_id%type;
v_sal employees.salary%type;
v_temp number(4,2);
begin
open emp_cursor;
fetch emp_cursor into v_empid,v_sal;
while emp_cursor%found loop
if v_sal < 5000 then v_temp:=0.05;
elsif v_sal < 10000 then v_temp:=0.03;
elsif v_sal < 15000 then v_temp:=0.02;
else v_temp:=0.01;
end if;
dbms_output.put_line(v_empid||','||v_sal);
update employees
set salary = salary * (1+v_temp)
where employee_id = v_empid;
fetch emp_cursor into v_empid,v_sal;
end loop;
close emp_cursor;
end;
用for循环实现
declare
cursor emp_cursor is select employee_id,salary from employees;
v_temp number(4,2);
begin
for c in emp_cursor loop
if c.salary <5000 then v_temp:=0.05;
elsif c.salary <10000 then v_temp:=0.03;
elsif c.salary <15000 then v_temp:=0.02;
else v_temp:=0.01;
end if;
update employees
set salary = salary * (1+v_temp)
where employee_id = c.employee_id;
end loop;
end;
隐式游标:更新员工salary(涨工资10),如果该员工没有找到,则打印“查无此人”信息:
begin
update employees
set salary = salary + 10
where employee_id = 1001;
if sql%notfound then dbms_output.put_line('查无此人');
end if;
end;
异常:
预定义异常:(有24个预定义异常,可查表)
declare
v_sal employees.salary%type;
begin
select salary into v_sal from employees
where employee_id > 100;
dbms_output.put_line(v_sal);
exception
when too_many_rows then dbms_output.put_line('输出的行数过多');
when others then dbms_output.put_line('出现其它的异常了');
end;
非预定义异常:
declare
e_deleteid_exception exception;
pragma exception_init(e_deleteid_exception,-2292);
begin
delete from employees
where employee_id = 100;
exception
when e_deleteid_exception then dbms_output.put_line('违反了完整性约束,故不能删除此用户');
when others then dbms_output.put_line('出现其它的异常了');
end;
用户自定义异常:
declare
e_sal_hight exception;
v_sal employees.salary%type;
begin
select salary into v_sal from employees where employee_id = 100;
if v_sal > 10000 then raise e_sal_hight;
end if;
exception
when e_sal_hight then dbms_output.put_line('工资太高了');
when others then dbms_output.put_line('出现其它的异常了');
end;
通过select...into...查询某人的工资,若没找到则打印出“未找到此数据”:
declare
v_sal employees.salary%type;
begin
select salary into v_sal from employees where employee_id = 1001;
exception
when no_data_found then dbms_output.put_line('未找到此数据');
when others then dbms_output.put_line('出现其它的异常了');
end;
更新指定员工工资,如工资小于300,则加100,对NO_DATA_FOUND异常,TOO_MANY_ROWS进行处理。
declare
v_sal employees.salary%type;
begin
select salary into v_sal from employees where employee_id = 1001;
if v_sal < 300 then update employees set salary = salary + 100 where employee_id =101;
end if;
exception
when no_data_found then dbms_output.put_line('未找到此数据');
when too_many_rows then dbms_output.put_line('输出的行数太多了');
when others then dbms_output.put_line('出现其它的异常了');
end;
自定义异常:
更新指定员工工资,增加100;若指定员工不在,则抛出异常:NO_RESULT;
declare
no_result exception;
begin
update employees set salary = salary + 100 where employee_id = 1001;
if sql%notfound then raise no_result;
end if;
exception
when no_result then dbms_output.put_line('查无此数据,更新失败');
when others then dbms_output.put_line('出现其它异常');
end;
存储过程:
写个简单的hello_world存储函数
create or replace function hello_world
return varchar2
is (相当于declare,可以在其后面定义变量、记录、游标)
begin
return 'helloworld';
end;
存储函数的调用:
begin
dbms_output.put_line(hello_world);
end;
或者:
select hello_world from dual;
带参数的存储函数:
create or replace function hello_world1(v_logo varchar2)
return varchar2
is
begin
return 'helloworld'||v_logo;
end;
调用:
select hello_world1('shellway') from dual
或者:
begin
dbms_output.put_line(hello_world1('shellway'));
end;
定义一个获取系统时间的函数:
create or replace function get_sysdate
return varchar2
is
begin
return to_char(sysdate,'yyyy-MM-dd HH24:mi:ss');
end;
定义带参数的函数,两个数相加
create or replace function add_param(v_num1 number,v_num2 number)
return number
is
v_num3 number(10);
begin
v_num3 := v_num1 + v_num2;
return v_num3;
end;
调用:
select add_param(2,5) from dual;
或者:
begin
dbms_output.put_line(add_param(5,4));
end;
定义一个函数:获取给定部门的工资总和,要求:部门号定义为参数,工资总额为返回值:
create or replace function get_sal(dept_id number)
return number
is
v_sumsal number(10) := 0;
cursor salary_cursor is select salary from employees where department_id = dept_id;
begin
for c in salary_cursor loop
v_sumsal := v_sumsal + c.salary;
end loop;
return v_sumsal;
end;
调用:
select get_sal(80) from dual;
定义一个函数:获取给定部门的工资总和 和 该部门的员工总数(定义为OUT类型的参数)。
要求:部门号定义为参数,工资总额定义为返回值。
create or replace function get_sal(dept_id number,total_count out number)
return number
is
v_sumsal number(10) := 0;
cursor salary_cursor is select salary from employees where department_id = dept_id;
begin
total_count := 0;
for c in salary_cursor loop
v_sumsal := v_sumsal + c.salary;
total_count := total_count + 1;
end loop;
return v_sumsal;
end;
调用:
declare
v_count number(4);
begin
dbms_output.put_line(get_sal(80,v_count));
dbms_output.put_line(v_count);
end;
定义一个存储过程:获取给定部门的工资总和(通过out参数),要求部门号和工资总额定义为参数。
(注意:存储过程和存储函数是不一样的,存储函数有返回值而存储过程没有,调用时候存储过程直接调用)
create or replace procedure get_sal1(dept_id number,sumsal out number)
is
cursor salary_cursor is select salary from employees where department_id = dept_id;
begin
sumsal := 0;
for c in salary_cursor loop
sumsal := sumsal + c.salary;
end loop;
dbms_output.put_line(sumsal);
end;
调用:
declare
v_sal number(10):=0;
begin
get_sal1(80,v_sal);
end;
对给定部门(作为输入参数)的员工进行加薪操作,若其到公司的时间在(?,95)期间,为其加薪5%
(95,98) 3%
(98,?) 1%
得到以下返回结果:为此次加薪公司每月额外付出多少成三(定义一个OUT型的输出参数)
create or replace procedure add_sal(dept_id number,temp out number)
is
cursor sal_cursor is select employee_id,salary,hire_date
from employees where department_id = dept_id;
v_temp number(4,2):=0;
begin
temp := 0;
for c in sal_cursor loop
if to_char(c.hire_date,'yyyy') < '1995' then v_temp:=0.05;
elsif to_char(c.hire_date,'yyyy') < '1998' then v_temp:=0.03;
else v_temp:=0.01;
end if;
update employees
set salary = salary * (1+v_temp)
where employee_id = c.employee_id;
temp := temp + c.salary*v_temp;
end loop;
dbms_output.put_line(temp);
end;
调用:
declare
v_i number(10):=0;
begin
add_sal(80,v_i);
end;
触发器:
触发事件:在INSERT,UPDATE,DELETE情况下会触发TRIGGER
触发时间:该TRIGGER是在触发事件发生之前(BEFORE)还是之后(AFTER)
触发器本身:该TRIGGER被触发之后的目的和意图,正是触发器本身要做的事情,如PL/SQL块
触发频率:有语句级(STATEMENT)触发器和行级(ROW)触发器
写一个简单的触发器:
create or replace trigger update_emp_trigger
after
update on employees
for each row (行级触发器,即每更新一条记录就会输出一次'helloworld',若没有这语句则是语句级触发器)
begin
dbms_output.put_line('helloworld');
end;
使用:new,:old修饰符:
1、
create table emp1
as
select employee_id,salary,email from employees where department_id = 80;
2、
create or replace trigger update_emp_trigger2
after
update on emp1
for each row
begin
dbms_output.put_line('old salary:'||:old.salary||'new salary:'||:new.salary);
end;
3、
update emp1 set salary = salary + 100 ;
编写一个触发器,在对my_emp记录进行删除的时候,在my_emp_bak表中备份对应的记录
1、创建my_emp表:
create table my_emp
as
select employee_id,salary from employees ;
2、创建my_emp_bak表:
create table my_emp_bak
as
select employee_id,salary from employees where 1=2;
3、检查创建的表中的记录:
select * from my_emp
select * from my_emp_bak
4、创建一个触发器:
create or replace trigger delete_emp_trigger
before
delete on my_emp
for each row
begin
insert into my_emp_bak
values(:old.employee_id,:old.salary);
end;
5、执行含有触发器时间的语句:
delete from my_emp
6、检查触发器执行后的结果:
select * from my_emp
select * from my_emp_bak
吾时而躬身自省,自省使知已之不足,知不足而奋起,未为晚也!
oracle从入门到精通复习笔记续集之PL/SQL(轻量版)的更多相关文章
- PL/SQL轻量版(一)——入门介绍
一.概述 1.概念对比: SQL:结构化查询语言(Structured Query Language)简称SQL(发音:/ˈes kjuː ˈel/ "S-Q-L"),是一种特殊目 ...
- oracle从入门到精通复习笔记
为方便大家跟着我的笔记练习,为此提供数据库表文件给大家下载:点我下载 描述一个表用 desc employees过滤重复的部门 select distinct department_id from e ...
- Oracle从入门到精通----学习笔记
书名:<Oracle从入门到精通:视频实战版>秦靖.刘存勇等编著 第4章 SQL基础 1.SQL语言分类 数据定义语言 --- DDL,Data Definition Language 数 ...
- php入门到精通(复习笔记)
第一章:php语言基础 1,标记风格: ①<?php echo “hello”;?> ②<script language="php">echo " ...
- 《Oracle 11g 入门到精通.明日科技.pdf》学习笔记
本博文整理者:刘军 本博文出自于: <Oracle 11g 入门到精通>一书 声明:1:转载请标注出处.本文不得作为商业活动.本人不负法律责任.违法者自负一切法律责任. ————————— ...
- 学习Oracle数据库入门到精通教程资料合集
任何大型信息系统,都需要有数据库管理系统作为支撑.其中,Oracle以其卓越的性能获得了广泛的应用.本合集汇总了学习Oracle数据库从入门到精通的30份教程资料. 资料名称 下载地址 超详细Orac ...
- Oracle从入门到精通 限定查询和排序查询的问题
视频课程:李兴华 Oracle从入门到精通视频课程 学习者:阳光罗诺 视频来源:51CTO学院 知识点 SQL语句的执行顺序 限定符号的使用. 具体内容: 如果想要对所选择的数据进行控制,就可以使 ...
- 干货分享!Oracle 的入门到精通 ~
Oracle Database,又名Oracle RDBMS,或简称Oracle.是甲骨文公司的一款关系数据库管理系统.它是在数据库领域一直处于领先地位的产品.可以说Oracle数据库系统是目前世界上 ...
- 查询oracle数据库,返回的数据是乱码。 PL/SQL正常。
查询oracle数据库,返回的数据是乱码. PL/SQL正常. 解决方案如下:
随机推荐
- 00.pip安装包
pip安装更换镜像源 pip install 包名 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com pip导出和导入 ...
- 使用androidstudio 分析内存泄漏
分析内存泄漏 http://www.jianshu.com/p/c49f778e7acf
- Ubuntu | Flask + Gunicorn + Nginx 部署服务器环境
现在我们手里有一个准备发布的项目,那么如何将他上传到你的服务器,并让外网访问呢? 前提: 1. 安装了Python环境 apt-get install python-dev 2. 安装Flask pi ...
- hdu2000 ASCII码排序【C++】
ASCII码排序 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- jQuery学习----简单介绍,基本使用,操作样式,动画
jQuery简单介绍 jq是js的插件库,说白了,jq就是一个js文件 凡事能用jq实现的,js都能实现.但是js能实现的,jq不一定能够实现 jq的引入 http://www.bootcdn.cn ...
- GeoTrust 企业(OV)型 增强版(EV) 多域名(SAN/UC) SSL证书
GeoTrust 企业(OV)型 增强版(EV) 多域名(SAN/UC)SSL证书(GeoTrust True BusinessID With EV Multi-Domain(SAN/UC) SSL ...
- JSON中getInt()和optInt()的区别
最近在用org.json这个包解析json的时候,发现谷歌提供两种不同的数据类型获取方法,比如说针对Int类型,提供了getInt()和optInt()两种方式,谷歌文档中的说明如下: 那么这两者有什 ...
- 学习笔记——TCP“三次握手”和“四次挥手”,简单介绍
TCP/IP协议中,TCP协议提供可靠的连接服务,采用“三次握手”建立一个连接. (1)第一次握手:客户端发送SYN包(SYN=j)到服务器,并进入SYN_SEND状态,等待服务器确认. (2)第二次 ...
- Jquery书写ajax
根据API学习本章 Jquery书写ajax 使用ajax发送表单到servlet,发送时显示等待图片,servlet处理完返回信息,在页面显示返回信息,并且隐藏等待图片 <%@ page la ...
- [bzoj3037/2068]创世纪[Poi2004]SZP_树形dp_并查集_基环树
创世纪 SZP bzoj-3037/2068 Poi-2004 题目大意:给你n个物品,每个物品可以且仅可以控制一个物品.问:选取一些物品,使得对于任意的一个被选取的物品来讲,都存在一个没有被选取的物 ...