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;