Oracle存储过程,触发器,游标

pl/sql基本的语法格式:
1:记录类型:type … is record(,);
2:流程控制:
2.1:条件判断(两种):
方式一:if … then elsif then … else … end if;
方式二:case … when … then … end;
2.2:循环结构(三种):
方式一:loop … exit when … end loop;
方式二:while … loop … end loop;
方式三:for i in … loop … end loop;
2.3:goto、exit
3:游标的使用(类似于Java中的Iterator)
4:异常的处理(三种方式)
5:会写一个存储函数(有返回值)、存储过程(没有返回值)
6:会写一个触发器

可转换的类型赋值
char转换为number:v_total := to_number(‘100.0’) + salary;
number转换为char:v_comm := to_char(‘123.45’)||‘元’;
字符转换为日期:v_date := to_date(‘2001.07.04’,‘yyyy.mm.dd’);
日期转换为字符串:v_to_day := to_char(sysdate,‘yyyy.mm.dd hh24:mi:ss’);

#PL/SQL中可以使用的SQL语句有:
INSERT,UPDATE,DELETE,SELECT …INTO,COMMIT,ROLLBACK,SAVEPOINT
在PL/SQL中只能使用SQL语句中的DML部分,不能用DDL部分。如果要在PL/SQL中使用DDL(如CREATE table等)
的话,只能以动态的方式来使用。

PL/SQL程序由三个块组成,即声明部分、执行部分、异常处理部分。
PL/SQL块的结构如下:
DECLARE
/声明部分:在此声明pl/sql用到的变量,类型及游标,以及局部的存储过程和函数/
BEGIN
/执行部分:过程及SQL语句,即程序的主要部分/
EXCEPTION
/执行异常部分:错误处理/
END;

#命名方法:
程序变量:V_name;V_name
程序常量:C_Name;C_company_name
游标变量:Name_cursor;Emp_cursor
异常变量:E_name;E_too_many
表类型:Name_table_type;Emp_record_type
表:Name_table;Emp
记录类型:Nmae_record;Emp_record
SQL*Plus替代变量:P_name;P_sal
绑定变量:G_name;G_year_al

#复合类型
Oracle在PL/SQL中还提供了一种复合类型——记录和表。复合类型:record、table、cursor。
记录(record)类型
记录类型是把逻辑相关的数据作为一个单元存储起来,称作PL/SQL RECORD的域(FIELD),其作用是存放互不相同但逻辑相关的信息。
declare
–声明一个记录类型
type emp_record is record(
v_sal emp.salary%type,
v_email emp.email%type,
v_hire_date emp.hire_date%type
);
–定义一个记录类型的成员变量
v_emp_record emp_record;
begin
–sql语句操作:select … into … from … where …
select salary,email,hire_date into v_emp_record from emp where emp_id=200;
–打印
dbms_output.put_line(v_emp_record.v_sal||’,’||v_emp_record.v_email||’,’||v_emp_record.v_hire_date);

end;

declare
–声明的变量、类型、游标
begin
–程序的执行部分(类似于Java里的main()方法)
exception
–针对begin块中出现的异常,提供处理的机制
–when … then …
–when … then …
end;

–declare

begin
dbms_output.put_line(‘hello world’);

end;

declare
–声明变量
v_sal number(10,2);
v_email varchar2(20);
v_hire_date date;
begin
–sql语句:select … into … from … where …
select salary,email,hire_date into v_sal,v_email,v_hire_date from emp where emp_id=200;
–打印
dbms_output.put_line(v_sal||’,’||v_email||’,’||v_hire_date);

end;

declare
v_sal emp.salary%type;–类型与表字段一致
begin
select salary into v_sal from emp where emp_id=200;
dbms_output.put_line(v_sal);

end;

declare
–变量、记录类型等的声明
v_sal number(8,2) := 0;
v_emp_id number(10);
v_email varchar2(20);
v_hire_date date;
begin
–程序的执行部分
select salary,emp_id,email,hire_date into v_sal,v_emp_id,v_email,v_hire_date
from emp
where emp_id=100;

dbms_output.put_line(v_emp_id||','||v_sal||','||v_email||','||v_hire_date);

end;

#记录类型
declare
–变量、记录类型等的声明
–声明一个记录类型
type emp_record is record(
v_sal number(8,2) :=0,
v_emp_id varchar2(10),
v_hire_date date
);
–声明一个记录类型的变量
v_emp_record emp_record;
begin
–程序的执行部分
select salary,emp_id,email,hire_date into v_emp_record
from emp
where emp_id=123;

dbms_output.put_line('emp_id:'||v_emp_record.v_emp_id||'salary:'||v_emp_record.v_sal||'email:'||v_emp_record.v_email||'hire_date:'||v_emp_record.v_hire_date);

end;

declare
type sal_record is record(
v_name varchar2(20),
v_salary number(10,2)
);

v_sal_record sal_record;

begin
v_sal_record.v_name :=‘刘德华’;
v_sal_record.v_salary :=120000;

dbms_output.put_line('name:'||v_sal_record.v_name||'salary:'||v_sal_record.v_salary);

end;

#动态获取参数
declare
v_emp_record emp%rowtype;
v_emp_id number(10);
begin
v_emp_id :=133;
select * into v_emp_record from emp
where emp_id=v_emp_id;

dbms_output.put_line('emp_id:'||v_emp_record.emp_id||'salary:'||v_emp_record.salary||'email:'||v_emp_record.email);

end;

#更新操作
declare
v_emp_id number(10);

begin
v_emp_id :=123;
update emp
set salary = salary + 100
where emp_id = v_emp_id;

dbms_output.put_line('执行成功');

end;

#流程控制
declare
v_sal emp.salary%type;
begin
select salary into v_sal from emp where emp_id=150;

if v_sal >= 10000 then dbms_outpu.put_line('salary >= 10000');
elsif v_sal >= 5000 then dbms_outpu.put_line('5000 <= salary < 10000');
else dbms_outpu.put_line('salary < 5000');
end if;

end;

#简化
declare
v_sal emp.salary%type;
v_emp varchar2(32);
begin
select salary into v_sal from emp where emp_id = 150;

if v_sal >= 10000 then v_emp := 'salary >= 10000';
elsif v_sal >= 5000 the v_emp := '5000 <= salary < 10000';
else v_emp := 'salary < 5000';
end if;

dbms_output.put_line(v_sal || ','||v_emp);

end;

#case when then
declare
v_sal emp.salary%type;
v_emp varchar2(30);
begin
select salary into v_sal from emp where emp_id=123;

v_emp :=
case trunc(v_sal/5000) when 0 then 'salary < 5000'
					   when 1 then '5000 <= salary < 10000'
					   else 'salary >= 10000'
end;

dbms_output.put_line(v_sal || ','||v_emp);

end;

#case when then
declare
v_job_id varchar2(10);
v_emp varchar2(12);
begin
select job_id into v_job_id from emp where emp_id=100;

v_emp:=
	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(v_job_id ||','||v_emp);

end;

#循环
–使用循环打印 1-100
–1:初始化条件;2:循环体;3:循环条件;4:迭代条件
declare
–初始化条件
v_i number(5):=1;
begin
loop
–2:循环体
dbms_output.put_line(v_i);
–3:循环条件
exit when v_i >= 100;
–4:迭代条件
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循环
–declare

begin
for c in 1…100 loop
dbms_output.put_line©;
end loop;

end;

#for循环reverse
–declare

begin
for c in reverse 1…10 loop
dbms_output.put_line©;
end loop;

end;

#while输出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 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_outpu.put_line(v_i);
	end if;
	
	v_flag := 1;
end loop;

end;

#goto输出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;
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;

#打印1-100的自然数,当打印到50时,跳出循环,输出"打印结束"
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;

游标
在PL/SQL程序中,对于处理多行记录的事务经常使用游标来实现。

#打印80部门所有员工的工资
declare
v_sal emp.salary%type;
v_empid emp.emp_id%type;
–定义游标
cursor emp_sal_cursor is select salary,emp_id from emp where dept_id = 80;
begin
–打开游标
open emp_sal_cursor;
–提取游标
fetch emp_sal_cursor into v_sal,v_empid;

while emp_sal_cursor%found loop
	dbms_output.put_line('emp_id:'||v_empid || 'salary:'||v_sal);
	fetch emp_sal_cursor into v_sal,v_empid;

end loop;
--关闭游标
close emp_sal_cursor;

end;

#定义一个记录类型
declare
–声明一个记录类型
type emp_record is record(
v_sal emp.salary%type,
v_emp_id emp.emp_id%type
);
–声明一个记录类型的变量
v_emp_record emp_record;
–定义游标
cursor emp_sal_cursor is select salary,emp_id from emp where dept_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('empid:'||v_emp_record.emp_id||'salary:'||v_emp_record.v_sal);
end loop;

end;

#for—游标
declare
–1、定义游标
cursor emp_sal_cursor is select emp_id,salary,hire_date from emp where dept_id=80;
begin
for c in emp_sal_cursor loop
dbms_output.put_line(‘emp_id:’||c.emp_id||‘salary:’||c.salary||‘hire_date:’||c.hire_date);
end loop;
end;

#使用游标(while)–调整员工工资
declre
–定义游标
cursor emp_sal_cursor is select emp_id,salary from emp;
–用于记录调整基数
v_temp number(4,2);

v_emp_id emp.emp_id%type;
v_sal emp.salary%type;

begin
open emp_sal_cursor;

fetch emp_sal_cursor into v_emp_id,v_sal;

while emp_sal_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_outpu.put_line(v_emp_id||','||v_sal);
	update emp
	set salary = salary * (1 + v_temp)
	where emp_id = v_emp_id;
	
	fetch emp_sal_cursor into v_emp_id,v_sal;
	
end loop;

close emp_sal_cursor;

end;

#使用游标(for)–调整员工工资
declare
–定义游标
cursor emp_sal_cursor is select emp_id,salary from emp;
–用于记录调整基数
v_temp number(4,2);

begin
for c in emp_sal_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 emp
	set salary = salary * (1 + v_temp)
	where emp_id = c.emp_id;
	
end loop;

end;

#带参数的游标
declare
–定义游标
cursor emp_sal_cursor(dept_id number,sal number) is
select salary + 100 sal,dept_id id
from emp
where dept_id = dept_id and salary > sal;
–定义基数变量
temp number(4,2);
begin
–处理游标的循环操作
for c in emp_sal_cursor(sal >= 4000,dept_id >= 80) loop
–判断员工的工资,执行update操作
–dbms_output.put_line(c.id||’,’||c.sal);

	if c.sal <= 5000 then temp := 0.05;
	elsif c.sal <= 10000 then temp := 0.03;
	elsif c.sal <= 15000 then temp := 0.02;
	else temp := 0.01;
	end if;
	
	dbms_outpu.put_line(c.id||','||c.sal||','||temp);
	--update emp set salary = salary * (1 + temp) where emp_id = c.id;
	
end loop;

end;

#隐式游标–更新员工工资
begin
update emp
set salary = salary + 10
where emp_id = 100;

if sql%notfound then dbms_output.put_line('查无此人');
end if;

end;

#异常的处理
declare
v_sal emp.salary%type;
begin
select salary into v_sal
from emp
where emp_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;

#ORA-02292:违反完整约束条件
declare
–1、定义异常
e_deleteid_exception exception;
–2、将定义好的异常与标准的Oracle错误联系起来,使用exception_init语句
pragma exception_init(e_deleteid_exception,-2292);
begin
delete from emp where emp_id = 000;
exception
–3、处理异常
when e_deleteid_exception then dbms_output.put_line(‘违反完整约束条件,故不可删除’);

end;

#自定义异常
declare
e_too_high_sal exception;
v_sal emp.salary%type;

begin
select salary from emp where emp_id = 100;

if v_sal > 10000 then
raise e_too_high_sal;
end if;

exception
when e_too_high_sal then dbms_outpu.put_line(‘工资太高了’);
end;

#综上异常
declare
e_too_high_sal exception;
v_sal emp.salary%type;

e_deleteid_exception exception;
pragma exception_init(e_deleteid_exception,-2292);

begin
delete from emp where emp_id = 000;

select salary from emp where emp_id = 100;

if v_sal > 10000 then 
raise e_too_high_sal;
end if;

exception
when e_too_high_sal then dbms_output.put_line(‘工资太高了’);
when e_deleteid_exception then dbms_output.put_line(‘违反完整约束条件,故不可删除’);
when others then dbms_output.put_line(‘发生其他错误’);

end;

#通过select … into … 抛出exception
declare
v_sal emp.salary%type;
begin
select salary into v_sal from emp where emp_id = 10001;
dbms_output.put_line(‘salary:’||v_sal);

exception
when no_date_found then dbms_output.put_line(‘查无此人’);

end;

#更新员工工资–exception处理
declare
v_sal emp.salary%type;

begin
select salary into v_sal from emp where emp_id = 100;

if v_sal < 300 then 
update emp set salary = salary + 100 
where emp_id = 100;
end if;

exception
when no_date_found then dbms_output.put_line(‘查无此人’);
when too_many_rows then dbms_output.put_line(‘输出的行数太多’);

end;

#自定义异常–更新员工工资
declre
–自定义异常
no_result exception;

begin
update emp set salary = salary + 100 where emp_id = 1001;

--使用隐式游标,抛出自定义异常
if sql%notfound then 
raise no_result;
end if;

exception
–处理程序抛出的异常
when no_result then dbms_output.put_line(‘更新失败’);

end;

存储函数

–函数的声明(有参数的写在小括号里)
create or replace function func_name(dept_id number,salary number)
–返回值类型
return number
is
–函数使用过程中,需要声明的变量、记录类型、游标的声明
begin
–函数体(可以实现增删改查等操作,返回值需要return)
exception
–处理函数执行过程的异常
end;

#函数–hello_world
create or replace function hello_world
return varchar2
is
begin
return ‘hello world’;
end;

#函数传参–hello_world
create or replace function hello_world(v_logo varchar2)
return varchar2
is
begin
–dbms_output.put_line(’—调用函数—’);
return 'hello world ’ || v_logo;
end;
–函数调用
select hello_world(‘oracle’) from dual;

#存储函数,返回当前的系统时间
create or replace function get_sysdate
return date
is
v_date date;
begin
v_date := sysdate;

return v_date;

end;
–函数调用
select get_sysdate from dual;

#定义带参函数–两数相加
create or replace function add_param(v_num1 number,v_num2 number)
return number
is
v_sum number(10);
begin
v_sum := v_num1 + v_num2;
return v_sum;
end;
–函数调用
select add_param(3,4) from dual;

#函数:获取给定部门的工资总和;要求部门号为参数,总工资定义为返回值
create or replace function get_sal(dept_id number)
return number
is
v_sumsal number(10) :=0;

cursor salary_cursor is select salary from emp where dept_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 get_sal(dept_id number,total_count out number)
return number
is
v_sumsal number(10) := 0;

cursor salary_cursor is select salary from emp where dept_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_num number(5) := 0;
begin
dbms_outpu.put_line(get_sal(80,v_num));
dbms_output.put_line(v_num);
end;

#对给定部门(作为输入参数)的员工进行加薪;
#得到返回结果:为此次加薪公司每月需要额外付出多少成本(定义一个OUT型的输出参数);
create or replace procedure add_sal(dept_id number,temp_sal out number)
is
cursor sal_cursor is select emp_id,salary,hire_date from emp where dept_id = dept_id;
v_i number(4,2) := 0;
begin
temp_sal := 0;
for c in sal_cursor loop
if to_char(c.hire_date,‘yyyy’) < ‘1995’ then v_i := 0.05;
elsif to_char(c.hire_date,‘yyyy’) < ‘1998’ then v_i := 0.03;
else v_i := 0.01;
end if;

	--1、更新工资
	update emp set salary  = salary * (1 + v_i) where emp_id = c.emp_id;
	--2、付出的成本
	temp_sal := temp_sal + c.salary * v_i;
end loop;

dbms_output.put_line('额外成本:'||temp_sal);

end;
–函数调用
declare
v_temp number(10) := 0;
begin
add_sal(80,v_temp);
end;

#触发器
触发事件:即在何种情况下触发 trigger,如:insert、update、delete。
触发时间:即该trigger是在触发事件发生之前(before)还是之后(after)触发。
触发器本身:该trigger被触发的目的和意图,触发器本身要做的事情。
触发器频率:触发器内定义的动作被执行的次数。即语句级(statement)触发器和行级(row)触发器。

#update–触发器
create or replace trigger update_emp_trigger
after
update on emp
–for each row
begin
dbms_output.put_line(‘hello world’);
end;

#insert–触发器
create or replace trigger insert_emp_trigger
after
insert on emp
for each row
begin
dbms_output.put_line(‘hello world’);
end;

#使用 :new,:old修饰符
create or replace trigger emp_trigger
after
update on emp
for each row
begin
dbms_output.put_line(‘old salary:’||:old.salary||’,new salary:’||:new.salary);
end;

#触发器:删除时在备份对应的记录
create or replace trigger delete_emp_trigger
before
delete on emp
for each row
begin
insert into mep_bak
values(:old.emp_id,old.salary);
end;

猜你喜欢

转载自blog.csdn.net/docsz/article/details/105277367
今日推荐