PL/SQL练习

简单结构

set serveroutput on;

DECLARE 
  v_name varchar2(20);
BEGIN
  v_name := 'hello';
  dbms_output.put_line(v_name);
END;

/

 

异常处理:

declare
v_num number :=0;
begin
v_num := 2/v_num;
dbms_output.put_line('devide function...');
exception
when others then
dbms_output.put_line('error....devide by'||v_num);
end;

 /

 

 

引用类型

declare
v_empno number(4);
--v_ename变量使用emp表ename字段的类型
v_ename emp.ename%type;
v_sal emp.sal%type;
begin
v_sal := 1000.123;
dbms_output.put_line(v_sal);
exception
when others then
dbms_output.put_line('error....');
end;

 

复合类型:

数组:table

declare
--声明一个table类型(看做数组),数组的值是emp表empno字段的类型,数组下标是binary——integer类型
type type_a is table of emp.empno%type index by binary_integer;
--声明一个type——a类型的数组
v_table_empno type_a;
begin

--下标可以为负数

v_table_empno(-1) := 1000;
v_table_empno(0) := 0000;
v_table_empno(1) := 1000;
v_table_empno(2) := 2000;
dbms_output.put_line('打印数组第二个值:'||v_table_empno(2));
exception
when others then
dbms_output.put_line('error....');
end;

 

 

对象:record

declare
--声明一个对象record,各个成员变量引用dept表的类型
type type_record_dept is record(
deptno dept.deptno%type,
dname dept.dname%type,
loc dept.loc%type
);
--声明上述类对应的一个对象
v_temp type_record_dept;
begin
--给对象赋值:
v_temp.deptno := 50;
v_temp.dname := 'dname---';
v_temp.loc := 'beijing';
dbms_output.put_line('打印v_temp对象:'||v_temp.deptno||', '||v_temp.dname||', '||v_temp.loc );
exception
when others then
dbms_output.put_line('error....');
end;

 

使用rowtype声明一个record对象:

declare
--声明一个对象record,她的所有字段同emp所有字段
v_emp emp%rowtype;
begin
--给对象赋值:
v_emp.empno := 1111;
v_emp.ename := 'sansan';
dbms_output.put_line('打印v_temp对象:'||v_emp.empno||', '||v_emp.ename);
exception
when others then
dbms_output.put_line('error....');
end;

 

 

select into

declare
--声明
v_ename emp.ename%type;
v_deptno emp.deptno%type;
begin
--给对象赋值,不用游标时这个select语句只能返回一条,而且必须返回一条数据
select ename,deptno into v_ename,v_deptno from emp where empno = 7369;
dbms_output.put_line('打印v_temp对象:'||v_ename||', '||v_deptno);
end;

 

 

执行DDL语句:execute immediate 

begin

--引号中,两个单引号代替一个单引号
execute immediate 'create table ttt(id varchar2(20),name varchar2(10) default ''sansan'')';
end;

 

分支判定:薪水小于1000加倍,大于则减半

declare
--声明
v_ename emp.ename%type;
v_sal emp.sal%type;
begin
--给对象赋值,不用游标时这个select语句只能返回一条,而且必须返回一条数据
select ename,sal into v_ename,v_sal from emp where empno = 1111;
if(v_sal < 1000) then
update emp set sal = sal*2 where empno=1111;
dbms_output.put_line('小于1000,加倍。。');
elsif(v_sal = 1000 )then
dbms_output.put_line('等于1000。。');
else
update emp set sal = sal/2 where empno=1111;
dbms_output.put_line('大于1000,减半。。');
end if;
commit;
end;

 

 

循环

--dowhile

declare
--声明
i binary_integer := 1;
begin
loop
dbms_output.put_line('第i='||i);
i := i+1;
exit when(i>=5);
end loop;
end;

 

 

--while

declare
--声明
i binary_integer := 1;
begin
while (i < 5) loop
dbms_output.put_line('第i='||i);
i := i+1;
end loop;
end;

 

--for 循环

declare
--声明
i binary_integer := 1;
begin
--顺序循环
for k in 1..5 loop
dbms_output.put_line('第k='||k);
end loop;

--逆序循环
for k in reverse 1..5 loop
dbms_output.put_line('第k='||k);
end loop;
end;

 

 

异常处理:

declare
--声明
v_ename emp.ename%type;
v_deptno emp.deptno%type;
begin
--给对象赋值,不用游标时这个select语句只能返回一条,而且必须返回一条数据
select ename,deptno into v_ename,v_deptno from emp where deptno=10;
dbms_output.put_line('打印v_temp对象:'||v_ename||', '||v_deptno);
exception 
--可以把这些异常记录在一张异常表中
when too_many_rows then
dbms_output.put_line('异常:记录数大于一条。。。'||SQLCODE||SQLERRM);
when no_data_found then
dbms_output.put_line('异常:没有记录。。。'||SQLCODE||SQLERRM);
when others then
dbms_output.put_line('其他异常。。。'||SQLCODE||SQLERRM);
end;

 

 

游标

declare
--声明一个游标,不会真正取数据
cursor c is
select * from emp;
--声明一个record
v_each c%rowtype;
begin
--打开游标,执行语句。游标指向第一条记录
open c;
--把游标指向的数据拿到v_each中,游标自动向下移动一个
fetch c into v_each;
dbms_output.put_line(v_each.ename);
--关闭游标
close c;
exception 
when others then
dbms_output.put_line('其他异常。。。'||SQLCODE||SQLERRM);
end;

 

 

--带参数的游标

declare
--声明一个游标,不会真正取数据
cursor c(v_deptno emp.deptno%type, v_job emp.job%type) is
select * from emp where deptno=v_deptno and job=v_job;
--声明一个record
v_each c%rowtype;
begin
--for循环会自动打开游标,把游标指向的数据拿到v_each中,游标自动向下移动一个
for v_each in c(30,'SALESMAN') loop
dbms_output.put_line(v_each.ename);
end loop;
--for循环会自动关闭游标
exception 
--可以把这些异常记录在一张异常表中
when others then
dbms_output.put_line('其他异常。。。'||SQLCODE||SQLERRM);
end;

 

 

--循环遍历游标

--for循环

declare
--声明一个游标,不会真正取数据
cursor c is
select * from emp;
--声明一个record
v_each c%rowtype;
begin
--打开游标,执行语句。游标指向第一条记录
--for循环会自动打开游标
--open c;
--for循环自动把游标指向的数据拿到v_each中,游标自动向下移动一个
for v_each in c loop
dbms_output.put_line(v_each.ename);
end loop;
--for循环会自动关闭游标
--close c;
exception 
--可以把这些异常记录在一张异常表中
when others then
dbms_output.put_line('其他异常。。。'||SQLCODE||SQLERRM);
end;

 

 

--while循环

declare
--声明一个游标,不会真正取数据
cursor c is
select * from emp;
--声明一个record
v_each c%rowtype;
begin
--打开游标,执行语句。游标指向第一条记录
open c;
--把游标指向的数据拿到v_each中,游标自动向下移动一个
fetch c into v_each;
--如果找找记录,继续向下执行
while(c%found) loop
dbms_output.put_line(v_each.ename);
--游标向后移动
fetch c into v_each;
end loop;
--关闭游标
close c;
exception 
--可以把这些异常记录在一张异常表中
when others then
dbms_output.put_line('其他异常。。。'||SQLCODE||SQLERRM);
end;

 

 

--dowhile循环

declare

--声明一个游标,不会真正取数据
cursor c is
select * from emp;
--声明一个record
--v_each c%rowtype;
begin
--打开游标,执行语句。游标指向第一条记录
open c;
--把游标指向的数据拿到v_each中,游标自动向下移动一个,自动声明v_each变量
loop
fetch c into v_each;

--最近的一条记录没有返回记录,退出
exit when(c%notfound);

dbms_output.put_line(v_each.ename);
end loop;
--关闭游标
close c;
exception 
--可以把这些异常记录在一张异常表中
when others then
dbms_output.put_line('其他异常。。。'||SQLCODE||SQLERRM);
end;

 

 

存储过程:

create or replace procedure ppp is替代declare,其他的一样。

执行用exec ppp;

或者:

begin

ppp;

end;

/

 

简单存储过程

--带参数的游标演示存储过程
create or replace procedure ppp is
--声明一个游标,不会真正取数据
cursor c(v_deptno emp.deptno%type, v_job emp.job%type) is
select * from emp where deptno=v_deptno and job=v_job;
--声明一个record
v_each c%rowtype;
begin
--for循环会自动打开游标,把游标指向的数据拿到v_each中,游标自动向下移动一个
for v_each in c(30,'SALESMAN') loop
dbms_output.put_line(v_each.ename);
end loop;
--for循环会自动关闭游标
exception 
--可以把这些异常记录在一张异常表中
when others then
dbms_output.put_line('其他异常。。。'||SQLCODE||SQLERRM);
end;

 



 

带参数的存储过程:

create or replace procedure ppp2(v_a in number, v_b number, v_c out number,v_d in out number) is
--三个参数,传入、传出、传入/传出三种类型。存储过程没有返回值。没有写默认是in
v_temp number := 5;
begin
if(v_a > v_b)then
   v_c := v_a;
   v_d := v_c*100;
elsif(v_a < v_b)then
   v_c := v_b;
   v_d := v_c*10;
end if;
exception 
--可以把这些异常记录在一张异常表中
when others then
dbms_output.put_line('其他异常。。。'||SQLCODE||SQLERRM);
end;

调用带参数的存储过程:

declare
c number;
d number := 10;
begin
ppp2(v_a => 2,v_b => 1,v_c => c,v_d => d);
dbms_output.put_line('c:'||c||'d:'||d);
end;

 

 

--函数有返回值,存储过程没有返回值
create or replace function sal_tax(v_sal number) return number is
begin
  if(v_sal < 3000) then
      return 0;
    elsif(v_sal < 5000) then
      return v_sal*0.1;
    else
      return v_sal*0.2;
  end if;
 end;

调用:

select sal, sal_tax(sal) from emp;

 

 

 综合使用的例子:

create table departments(
    DEPARTMENT_ID NUMBER(4) primary key,
    DEPARTMENT_NAME VARCHAR2(30),
    MANAGER_ID NUMBER(6),
    LOCATION_ID NUMBER(4)
    );

insert into departments values(1,'技术部',1,1);
insert into departments values(2,'人事部',2,2);
insert into departments values(3,'市场部',3,3);
insert into departments values(4,'财务部',4,4);

 

create table employees(
    EMPLOYEE_ID NUMBER(6) primary key,
    FIRST_NAME VARCHAR2(20),
    LAST_NAME VARCHAR2(25),
    EMAIL VARCHAR2(25),
    PHONE_NUMBER VARCHAR2(20),
    HIRE_DATE DATE,
    JOB_ID VARCHAR2(10),
    SALARY NUMBER(8,2),
    COMMISSION_PCT NUMBER(2,2),
    DEPARTMENT_ID NUMBER(4) references departments(DEPARTMENT_ID)
    );

insert into employees(EMPLOYEE_ID,FIRST_NAME,LAST_NAME,SALARY,DEPARTMENT_ID) values(1,'JIA','JENNY',3000,1);
insert into employees(EMPLOYEE_ID,FIRST_NAME,LAST_NAME,SALARY,DEPARTMENT_ID) values(2,'guan','rose',4000,3);
insert into employees(EMPLOYEE_ID,FIRST_NAME,LAST_NAME,SALARY,DEPARTMENT_ID) values(3,'xu','mike',2000,2);
insert into employees(EMPLOYEE_ID,FIRST_NAME,LAST_NAME,SALARY,DEPARTMENT_ID) values(4,'zhang','billy',1000,2);
insert into employees(EMPLOYEE_ID,FIRST_NAME,LAST_NAME,SALARY,DEPARTMENT_ID) values(5,'jin','dede',5000,1);

 

声明一个存储过程,输入工资数sal,小于sal则+1,小于sal+1000则不变,大于则-1.

CREATE OR REPLACE PROCEDURE changeSal(sal in number,cnt out number)IS
  --定义一个EMPLOYEES表对应的类型
  eachOne EMPLOYEES%ROWTYPE;
  --定义一个record
  TYPE type_record IS RECORD(
    ename varchar2(45),
    sal EMPLOYEES.SALARY%type
  );
  --定义一个上述record类型的对象
  temp type_record;
  --定义一个数字
  total NUMBER := 0;
  --定义一个游标
  CURSOR c IS select * from employees;
BEGIN
  OPEN c;
  --读取游标第一个值,游标向后移动
  fetch c into eachOne;
  dbms_output.put_line('存储过程正在执行,小于'||sal||'的薪水+1,小于'||(sal+1000)||'的薪水不变,大于的-1...');
  while(c%found)loop
    --拼接名字全称
    temp.ename := eachOne.first_name||eachOne.last_name;
    --变化薪水
    if (eachOne.salary < sal)then
      --变化了,计数
      total := total+1;
      temp.sal := eachOne.salary + 1;
    elsif(eachOne.salary < sal+1000)then
      temp.sal := eachOne.salary;
    else
      --变化了,计数
      total := total+1;
      temp.sal := eachOne.salary -1;
    end if;
    dbms_output.put_line('名字全称:'||temp.ename||', 变化后的薪水:'||temp.sal);
    --游标向后移动
    fetch c into eachOne;
  end loop;
  CLOSE c;
  cnt := total;
 END;--END PROCEDURE

 

调用:

declare
cnt1 number;
begin
changeSal(sal => 2000,cnt=>cnt1);
dbms_output.put_line('变化的结果:'||cnt1);
end;

结果:

SQL> declare
  2  cnt1 number;
  3  begin
  4  changeSal(sal => 2000,cnt=>cnt1);
  5  dbms_output.put_line('变化的结果:'||cnt1);
  6  end;
  7  /
存储过程正在执行,小于2000的薪水+1,小于3000的薪水不变,大于的-1...
名字全称:JIAJENNY, 变化后的薪水:2999
名字全称:guanrose, 变化后的薪水:3999
名字全称:xumike, 变化后的薪水:2000
名字全称:zhangbilly, 变化后的薪水:1001
名字全称:jindede, 变化后的薪水:4999
变化的结果:4
PL/SQL procedure successfully completed

 

posted @ 2013-09-02 10:20  大树的博客  Views(337)  Comments(0Edit  收藏  举报