加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

oracle复习笔记之PL/SQL程序所要知道的知识点

发布时间:2021-11-26 17:26:27 所属栏目:PHP教程 来源:互联网
导读:PL/SQL的基本语法、记录类型、流程控制、游标的使用、 异常处理机制、存储函数/存储过程、触发器。 为方便大家跟着我的笔记练习,为此提供数据库表文件给大家下载 为了要有输出的结果,在写PL/SQL程序前都在先运行这一句: set serveroutput on 结构: decla

PL/SQL的基本语法、记录类型、流程控制、游标的使用、
 
异常处理机制、存储函数/存储过程、触发器。
 
为方便大家跟着我的笔记练习,为此提供数据库表文件给大家下载
 
为了要有输出的结果,在写PL/SQL程序前都在先运行这一句:
set serveroutput on
结构:
declare
--声明变量、类型、游标
begin
--程序的执行部分(类似于java里的main()方法)
exception
--针对begin块中出现的异常,提供处理的机制
--when...then...
--when...then...
end;
举例1:
 
1
declare
2
  v_sal number(10); (注意每句话后面别忘记了分号,跟java中的一样)
3
begin
4
  select salary into v_sal from employees where employee_id = 100;
5
  dbms_output.put_line(v_sal);
6
end;
举例2:
 
01
declare
02
  v_sal number(10); (注意,这里声明的空间大小不能比原表中的小)
03
  v_email varchar2(20);
04
  v_hire_date date;
05
begin
06
  select salary,email,hire_date into v_sal,v_email,v_hire_date from employees where employee_id =
07
100;
08
  dbms_output.put_line(v_sal||','||v_email||','||v_hire_date);
09
end;
10
或者:
11
declare
12
  v_sal employees.salary%type;
13
  v_email employees.email%type;
14
  v_hire_date employees.hire_date%type;
15
begin
16
  select salary,email,hire_date into v_sal,v_email,v_hire_date from employees where employee_id =
17
100;
18
  dbms_output.put_line(v_sal||','||v_email||','||v_hire_date);
19
end;
记录:
 
01
declare
02
  type emp_record is record(
03
   v_sal employees.salary%type,
04
   v_email employees.email%type,
05
   v_hire_date employees.hire_date%type
06
  );
07
  v_emp_record emp_record;
08
begin
09
  select salary,email,hire_date into v_emp_record from employees where employee_id = 100;
10
  dbms_output.put_line(v_emp_record.v_sal||','||v_emp_record.v_email||','||
11
  v_emp_record.v_hire_date);
12
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.会写一个触发器
 
复习记录类型:
 
01
declare
02
type emp_record is record(
03
  -- v_emp_id employees.employee_id%type,
04
  -- v_sal employees.salary%type
05
  v_emp_id number(10) := 120,
06
  v_sal number(10,2) :=12000
07
);
08
  v_emp_record emp_record;
09
begin
10
  -- select employee_id,salary into v_emp_record from employees where employee_id = 123;
11
  dbms_output.put_line('employee_id:'||v_emp_record.v_emp_id||' '||'salary:'||
12
  v_emp_record.v_sal);
13
end;
也可以升级一下,要是想对表的所有列都输出,则:(须注意输出的列名要跟表中的列名要一样)
 
01
declare
02
  v_emp_record employees%rowtype;
03
begin
04
  select * into v_emp_record from employees where employee_id = 123;
05
  dbms_output.put_line('employee_id:'||v_emp_record.employee_id||' '||'salary:'||
06
  v_emp_record.salary);
07
end;
08
使用记录来执行update操作:
09
declare
10
  v_emp_id number(10);
11
begin
12
  v_emp_id :=123;
13
  update employees
14
  set salary = salary + 100
15
  where employee_id = v_emp_id;
16
  dbms_output.put_line('执行成功!~~');
17
end;
流程控制:
查询150号员工的工资,若其工资大于或等于10000 则打印‘salary >= 10000';
若在5000到10000之间,则打印‘5000 <= salary <10000';否则打印‘salary < 5000'
 
01
declare
02
  v_sal employees.salary%type;
03
begin
04
  select salary into v_sal from employees where employee_id =150;
05
  if v_sal >= 10000 then dbms_output.put_line('salary >= 10000');
06
  elsif v_sal > 5000 then dbms_output.put_line('10000 > salary >= 5000');
07
  else dbms_output.put_line('salary < 5000');
08
  end if;
09
  dbms_output.put_line('salary:'||v_sal);
10
end;
11
利用case ... when ... then ... when ...then ... else ... end实现上题;
12
declare
13
  v_sal employees.salary%type;
14
  v_temp varchar2(20);
15
begin
16
  select salary into v_sal from employees where employee_id =150;
17
  v_temp :=
18
  case trunc(v_sal/5000) when 0 then 'salary < 5000'
19
                  when 1 then '5000 <= salary < 10000'
20
                  else 'salary >= 10000'
21
                  end;
22
  dbms_output.put_line('salary:'||v_sal||' '||v_temp);
23
end;
 
查询出122号员工的job_id,若其值为 ‘IT_PROG', 则打印‘GRADE:A'
                                                ‘AC_MGT', 则打印‘GRADE:B'
                                                ‘AC_ACCOUNT', 则打印‘GRADE:B'
                                                 否则打印‘GRADE:D'
 
01
declare
02
  v_job_id employees.job_id%type;
03
  v_temp varchar2(20);
04
begin
05
  select job_id into v_job_id from employees where employee_id =122;
06
  v_temp :=
07
  case v_job_id when 'IT_PROG' then 'A'
08
            when 'AC_MGT' then 'B'
09
            when 'AC_ACCOUNT' then 'C'
10
            else 'D'
11
            end;
12
  dbms_output.put_line('job_id:'||v_job_id||' '||v_temp);
13
end;
使用循环语句打印:1-100
 
01
declare
02
  v_i number(5) :=1;
03
 
04
begin
05
  loop
06
  dbms_output.put_line(v_i);
07
  exit when v_i >=100;
08
  v_i := v_i + 1;
09
  end loop;
10
end;
11
使用while实现:
12
declare
13
  v_i number(5) :=1;
14
begin
15
  while v_i <= 100 loop
16
   dbms_output.put_line(v_i);
17
   v_i := v_i + 1;
18
  end loop;
19
end;
20
使用for...in...loop...end loop;实现:
21
begin
22
  for c in 1..100 loop
23
   dbms_output.put_line(c);
24
  end loop;
25
end;
 
输出2-100之间的质数
 
01
declare
02
  v_i number(3):= 2;
03
  v_j number(3):= 2;
04
  v_flag number(1):= 1;
05
begin
06
  while v_i<=100 loop
07
   while v_j<=sqrt(v_i) loop
08
    if mod(v_i,v_j)=0 then v_flag:=0;
09
    end if;
10
    v_j:= v_j+1;
11
   end loop;
12
  if v_flag = 1 then dbms_output.put_line(v_i);
13
  end if;
14
  v_j :=2;
15
  v_i := v_i + 1;
16
  v_flag := 1;
17
  end loop;
18
end;
利用for循环实现输出2-100之间的质数:
 
01
declare
02
  v_flag number(1):= 1;
03
begin
04
  for v_i in 2..100 loop
05
   for v_j in 2..sqrt(v_i) loop
06
    if mod(v_i,v_j)=0 then v_flag:=0;
07
    end if;
08
   end loop;
09
   if v_flag=1 then dbms_output.put_line(v_i);
10
   end if;
11
   v_flag := 1;
12
  end loop;
13
end;
可以用goto改进一下:
 
01
declare
02
  v_flag number(1):= 1;
03
begin
04
  for v_i in 2..100 loop
05
    for v_j in 2..sqrt(v_i) loop
06
     if mod(v_i,v_j)=0 then v_flag:=0;
07
     goto label;
08
     end if;
09
   end loop;
10
   <<label>>
11
   if v_flag=1 then dbms_output.put_line(v_i);
12
   end if;
13
   v_flag := 1;
14
  end loop;
15
end;
打印1-100的自然数,当打印到50时,跳出循环 ,输出‘打印结束':
 
01
begin
02
  for i in 1..100 loop
03
   if i=50 then goto label;
04
   end if;
05
  dbms_output.put_line(i);
06
  end loop;
07
<<label>>
08
  dbms_output.put_line('打印结束');
09
end;
10
或者:
11
begin
12
  for i in 1..100 loop
13
   if i=50 then dbms_output.put_line('打印结束');
14
   exit;
15
   end if;
16
  dbms_output.put_line(i);
17
  end loop;
18
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;
可以进行优化如下:
 
01
declare
02
v_empid employees.employee_id%type;
03
v_lastName employees.last_name%type;
04
v_sal employees.salary%type;
05
cursor emp_sal_cursor is select employee_id,last_name,salary from employees where
06
department_id = 80;
07
begin
08
open emp_sal_cursor;
09
fetch emp_sal_cursor into v_empid,v_lastName,v_sal;
10
while emp_sal_cursor%found loop
11
dbms_output.put_line('employee_id:'||v_empid||', '||'last_name:'||v_lastName||',
12
'||'salary:'||v_sal);
13
fetch emp_sal_cursor into v_empid,v_lastName,v_sal;
14
end loop;
15
close emp_sal_cursor;
16
end;
或者使用记录再优化一下:
 
01
declare
02
type emp_record is record(
03
v_empid employees.employee_id%type,
04
v_lastName employees.last_name%type,
05
v_sal employees.salary%type
06
);
07
v_emp_record emp_record;
08
cursor emp_sal_cursor is select employee_id,last_name,salary from employees where
09
department_id = 80;
10
begin
11
open emp_sal_cursor;
12
fetch emp_sal_cursor into v_emp_record;
13
while emp_sal_cursor%found loop
14
dbms_output.put_line('employee_id:'||v_emp_record.v_empid||', '||'last_name:'||
15
v_emp_record.v_lastName||', '||'salary:'||v_emp_record.v_sal);
16
fetch emp_sal_cursor into v_emp_record;
17
end loop;
18
close emp_sal_cursor;
19
end;
可以使用for循环最优化:(注意:在for循环中它会自动的打开游标、提取游标,当提取完里面的数据后也会自动
的关闭游标)
 
1
declare
2
cursor emp_sal_cursor is select employee_id,last_name,salary from employees where
3
department_id = 80;
4
begin
5
for c in emp_sal_cursor loop
6
dbms_output.put_line('employee_id:'||c.employee_id||', '||'last_name:'||c.last_name||',
7
'||'salary:'||c.salary);
8
end loop;
9
end;
 
利用游标,调整公司中员工的工资:
工资范围            调整基数
0 - 5000              5%
5000 - 10000       3%
10000 - 15000     2%
15000 -               1%
实现:
 
01
declare
02
  cursor emp_cursor is select employee_id,salary from employees;
03
  v_empid employees.employee_id%type;
04
  v_sal employees.salary%type;
05
  v_temp number(4,2);
06
begin
07
  open emp_cursor;
08
  fetch emp_cursor into v_empid,v_sal;
09
  while emp_cursor%found loop
10
   if v_sal < 5000 then v_temp:=0.05;
11
   elsif v_sal < 10000 then v_temp:=0.03;
12
   elsif v_sal < 15000 then v_temp:=0.02;
13
   else v_temp:=0.01;
14
   end if;
15
  dbms_output.put_line(v_empid||','||v_sal);
16
  update employees
17
  set salary = salary * (1+v_temp)
18
  where employee_id = v_empid;
19
  fetch emp_cursor into v_empid,v_sal;
20
  end loop;
21
  close emp_cursor;
22
end;
用for循环实现
 
01
declare
02
  cursor emp_cursor is select employee_id,salary from employees;
03
  v_temp number(4,2);
04
begin
05
  for c in emp_cursor loop
06
   if c.salary <5000 then v_temp:=0.05;
07
   elsif c.salary <10000 then v_temp:=0.03;
08
   elsif c.salary <15000 then v_temp:=0.02;
09
   else v_temp:=0.01;
10
  end if;
11
  update employees
12
  set salary = salary * (1+v_temp)
13
  where employee_id = c.employee_id;
14
  end loop;
15
end;
隐式游标:更新员工salary(涨工资10),如果该员工没有找到,则打印“查无此人”信息:
 
1
begin
2
  update employees
3
  set salary = salary + 10
4
  where employee_id = 1001;
5
   if sql%notfound then dbms_output.put_line('查无此人');
6
   end if;
7
end;
异常:
预定义异常:(有24个预定义异常,可查表)
 
01
declare
02
  v_sal employees.salary%type;
03
begin
04
  select salary into v_sal from employees
05
  where employee_id > 100;
06
  dbms_output.put_line(v_sal);
07
exception
08
  when too_many_rows then dbms_output.put_line('输出的行数过多');
09
  when others then dbms_output.put_line('出现其它的异常了');
10
end;
非预定义异常:
 
01
declare
02
  e_deleteid_exception exception;
03
  pragma exception_init(e_deleteid_exception,-2292);
04
begin
05
  delete from employees
06
  where employee_id = 100;
07
exception
08
  when e_deleteid_exception then dbms_output.put_line('违反了完整性约束,故不能删除此用户');
09
  when others then dbms_output.put_line('出现其它的异常了');
10
end;
用户自定义异常:
 
01
declare
02
  e_sal_hight exception;
03
  v_sal employees.salary%type;
04
begin
05
  select salary into v_sal from employees where employee_id = 100;
06
  if v_sal > 10000 then raise e_sal_hight;
07
  end if;
08
exception
09
  when e_sal_hight then dbms_output.put_line('工资太高了');
10
  when others then dbms_output.put_line('出现其它的异常了');
11
end;
通过select...into...查询某人的工资,若没找到则打印出“未找到此数据”:
 
01
declare
02
  v_sal employees.salary%type;
03
begin
04
  select salary into v_sal from employees where employee_id = 1001;
05
exception
06
  when no_data_found then dbms_output.put_line('未找到此数据');
07
  when others then dbms_output.put_line('出现其它的异常了');
08
end;
09
更新指定员工工资,如工资小于300,则加100,对NO_DATA_FOUND异常,TOO_MANY_ROWS进行处理。
10
declare
11
  v_sal employees.salary%type;
12
begin
13
  select salary into v_sal from employees where employee_id = 1001;
14
  if v_sal < 300 then update employees set salary = salary + 100 where employee_id =101;
15
  end if;
16
exception
17
  when no_data_found then dbms_output.put_line('未找到此数据');
18
  when too_many_rows then dbms_output.put_line('输出的行数太多了');
19
  when others then dbms_output.put_line('出现其它的异常了');
20
end;
自定义异常:
更新指定员工工资,增加100;若指定员工不在,则抛出异常:NO_RESULT;
 
01
declare
02
  no_result exception;
03
begin
04
  update employees set salary = salary + 100 where employee_id = 1001;
05
  if sql%notfound then raise no_result;
06
  end if;
07
exception
08
  when no_result then dbms_output.put_line('查无此数据,更新失败');
09
  when others then dbms_output.put_line('出现其它异常');
10
end;
 
存储过程:
写个简单的hello_world存储函数
 
01
create or replace function hello_world
02
return varchar2
03
is (相当于declare,可以在其后面定义变量、记录、游标)
04
begin
05
  return 'helloworld';
06
end;
07
存储函数的调用:
08
begin
09
  dbms_output.put_line(hello_world);
10
end;
11
或者:
12
select hello_world from dual;
 
带参数的存储函数:
 
01
create or replace function hello_world1(v_logo varchar2)
02
return varchar2
03
is
04
begin
05
  return 'helloworld'||v_logo;
06
end;
07
调用:
08
select hello_world1('shellway') from dual
09
或者:
10
begin
11
  dbms_output.put_line(hello_world1('shellway'));
12
end;
 
定义一个获取系统时间的函数:
 
1
create or replace function get_sysdate
2
return varchar2
3
is
4
begin
5
  return to_char(sysdate,'yyyy-MM-dd HH24:mi:ss');
6
end;
 
定义带参数的函数,两个数相加
 
01
create or replace function add_param(v_num1 number,v_num2 number)
02
return number
03
is
04
  v_num3 number(10);
05
begin
06
  v_num3 := v_num1 + v_num2;
07
  return v_num3;
08
end;
09
调用:
10
select add_param(2,5) from dual;
11
或者:
12
begin
13
  dbms_output.put_line(add_param(5,4));
14
end;
 
定义一个函数:获取给定部门的工资总和,要求:部门号定义为参数,工资总额为返回值:
 
01
create or replace function get_sal(dept_id number)
02
return number
03
is
04
  v_sumsal number(10) := 0;
05
  cursor salary_cursor is select salary from employees where department_id = dept_id;
06
begin
07
  for c in salary_cursor loop
08
  v_sumsal := v_sumsal + c.salary;
09
  end loop;
10
  return v_sumsal;
11
end;
12
调用:
13
select get_sal(80) from dual;
 
定义一个函数:获取给定部门的工资总和 和 该部门的员工总数(定义为OUT类型的参数)。
要求:部门号定义为参数,工资总额定义为返回值。
 
01
create or replace function get_sal(dept_id number,total_count out number)
02
return number
03
is
04
 v_sumsal number(10) := 0;
05
 cursor salary_cursor is select salary from employees where department_id = dept_id;
06
begin
07
  total_count := 0;
08
  for c in salary_cursor loop
09
    v_sumsal := v_sumsal + c.salary;
10
    total_count := total_count + 1;
11
  end loop;
12
  return v_sumsal;
13
end;
14
调用:
15
declare
16
  v_count number(4);
17
begin
18
  dbms_output.put_line(get_sal(80,v_count));
19
  dbms_output.put_line(v_count);
20
end;
 
定义一个存储过程:获取给定部门的工资总和(通过out参数),要求部门号和工资总额定义为参数。
(注意:存储过程和存储函数是不一样的,存储函数有返回值而存储过程没有,调用时候存储过程直接调用)
 
01
create or replace procedure get_sal1(dept_id number,sumsal out number)
02
is
03
 cursor salary_cursor is select salary from employees where department_id = dept_id;
04
begin
05
 sumsal := 0;
06
 for c in salary_cursor loop
07
   sumsal := sumsal + c.salary;
08
 end loop;
09
 dbms_output.put_line(sumsal);
10
end;
11
调用:
12
declare
13
  v_sal number(10):=0;
14
begin
15
 get_sal1(80,v_sal);
16
end;
 
对给定部门(作为输入参数)的员工进行加薪操作,若其到公司的时间在(?,95)期间,为其加薪5%
 
                                                                                          (95,98)                  3%
 
                                                                                          (98,?)                   1%
得到以下返回结果:为此次加薪公司每月额外付出多少成三(定义一个OUT型的输出参数)
 
01
create or replace procedure add_sal(dept_id number,temp out number)
02
is
03
  cursor sal_cursor is select employee_id,salary,hire_date
04
  from employees where department_id = dept_id;
05
  v_temp number(4,2):=0;
06
begin
07
  temp := 0;
08
  for c in sal_cursor loop
09
    if to_char(c.hire_date,'yyyy') < '1995' then v_temp:=0.05;
10
    elsif to_char(c.hire_date,'yyyy') < '1998' then v_temp:=0.03;
11
    else v_temp:=0.01;
12
    end if;
13
 
14
  update employees
15
  set salary = salary * (1+v_temp)
16
  where employee_id = c.employee_id;
17
 
18
  temp := temp + c.salary*v_temp;
19
  end loop;
20
  dbms_output.put_line(temp);
21
end;
22
调用:
23
declare
24
  v_i number(10):=0;
25
begin
26
  add_sal(80,v_i);
27
end;
触发器:
触发事件:在INSERT,UPDATE,DELETE情况下会触发TRIGGER
触发时间:该TRIGGER是在触发事件发生之前(BEFORE)还是之后(AFTER)
触发器本身:该TRIGGER被触发之后的目的和意图,正是触发器本身要做的事情,如PL/SQL块
触发频率:有语句级(STATEMENT)触发器和行级(ROW)触发器
写一个简单的触发器:
 
1
create or replace trigger update_emp_trigger
2
after
3
  update on employees
4
for each row (行级触发器,即每更新一条记录就会输出一次'helloworld',若没有这语句则是语句级触发器)
5
begin
6
  dbms_output.put_line('helloworld');
7
end;
 
使用:new,:old修饰符:
 
01
1、
02
create table emp1
03
as
04
select employee_id,salary,email from employees where department_id = 80;
05
2、
06
create or replace trigger update_emp_trigger2
07
after
08
  update on emp1
09
for each row
10
begin
11
  dbms_output.put_line('old salary:'||:old.salary||'new salary:'||:new.salary);
12
end;
13
3、
14
update emp1 set salary = salary + 100 ;
 
编写一个触发器,在对my_emp记录进行删除的时候,在my_emp_bak表中备份对应的记录
 
01
1、创建my_emp表:
02
create table my_emp
03
as
04
select employee_id,salary from employees ;
05
2、创建my_emp_bak表:
06
create table my_emp_bak
07
as
08
select employee_id,salary from employees where 1=2;
09
3、检查创建的表中的记录:
10
select * from my_emp
11
select * from my_emp_bak
12
4、创建一个触发器:
13
create or replace trigger delete_emp_trigger
14
before
15
  delete on my_emp
16
for each row
17
begin
18
  insert into my_emp_bak
19
  values(:old.employee_id,:old.salary);
20
end;
21
5、执行含有触发器时间的语句:
22
delete from my_emp
23
6、检查触发器执行后的结果:
24
select * from my_emp
25
select * from my_emp_bak
 

(编辑:云计算网_泰州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读