1. 程式人生 > >Oracle實驗四 PLSQL程式設計

Oracle實驗四 PLSQL程式設計

1、PL/SQL語句塊
定義一個包含宣告、執行和異常處理的語句塊
查詢EMP表中職工號7788的工資,輸出工資的值並且如果工資小於3000那麼把工資更改為3000,異常部分對NO_DATA_FOUND異常進行
處理,輸出沒有該員工。如果想執行緩衝區的內容,那麼可以用RUN命令或者/命令;serveroutput需要設定為on

declare
  v_sal emp.sal%type;
begin
  select sal into v_sal from emp where empno=7369;
  if v_sal<3000 then
  update emp set sal=3100 where empno=7369;
  end if;
exception
     when no_data_found then
     dbms_output.put_line('There is not such a employee');
end;

2、變數、資料型別和系統函式的使用
     1)定義三個變數,一個變數的初始值為字串‘你好,’第二個字串賦值為‘我是XXX’,這裡寫上自己的名字,第三個變數
為前兩個變數中的字串連線之後的結果。輸出第三個變數的值。(選做)

declare  
v_n1 varchar2(20):='你好';
  v_n2 varchar2(20):='我是張洋洋';
  v_n3 varchar2(30):=v_n1||v_n2;
begin
  dbms_output.put_line(v_n3);
end;

2)將自己的名字作為字串求出其長度,將長度與數字2進行比較,如果不大於2,輸出‘我的名字是兩個字’。(選做)

declare
  v_n varchar2(20):='張洋洋';
begin
  if length(v_n)<=2 then
  dbms_output.put_line('我的名字是兩個字');
  end if;
end;

 3)定義三個變數,分別用來儲存emp表中的ename,sal,job三個列的值,並對其進行輸出;要求用兩種方式實現
(%type型別和非%type型別)。

declare
  cursor c_emp is select ename,sal,job from emp;
  v_emp c_emp%rowtype;
begin
  open c_emp;
  loop
  fetch c_emp into v_emp;
  exit when c_emp%notfound;
  dbms_output.put_line(v_emp.ename||' '||v_emp.sal||' '||v_emp.job);
  end loop;
  close c_emp;
end;
declare
  v_ename emp.ename%type;
  v_sal emp.sal%type;
  v_job emp.job%type;
  cursor v_emp is select ename,sal,job from emp;
begin
   open v_emp;
   loop
   fetch v_emp into v_ename,v_sal,v_job;
   exit when v_emp%notfound;
   dbms_output.put_line(v_ename||' '||v_sal||' '||v_job);
   end loop;
   close v_emp;
end;
declare
  v_ename varchar2(20);
  v_sal varchar2(20);
  v_job varchar2(20);
  cursor v_emp is select ename,sal,job from emp;
begin
   open v_emp;
   loop
   fetch v_emp into v_ename,v_sal,v_job;
   exit when v_emp%notfound;
   dbms_output.put_line(v_ename||' '||v_sal||' '||v_job);
   end loop;
   close v_emp;
end;

4)建立一個記錄型別v_record,型別包含v_name,v_salary,v_job,v_deptno等分量,要求記錄型別中各個分量的資料型別
和emp表中ename,sal,job,deptno列的資料型別一致(%type實現)。建立一個變數,變數型別為v_ record,讀取EMP表
中職工號為7788的ename,sal,job,deptno為該變數賦值,輸出該變數的值。

declare
  cursor v_emp is select ename,sal,job,deptno from emp where empno=7788;
  v_record v_emp%rowtype;
begin
  open v_emp;
  fetch v_emp into v_record;
  dbms_output.put_line(v_record.ename||' '||v_record.sal||' '||v_record.job||' '||v_record.deptno);
  close v_emp;
end;

3、條件語句的使用
分別用IF語句和CASE語句實現以下要求:輸入一個員工號,修改該員工的工資,如果該員工職位是CLERK,工資增加100;
若為SALESMAN,工資增加160;若為ANALYST,工資增加200;否則增加300。
1.if-else實現

declare
  v_empno emp.empno%type;
  v_job emp.job%type;
  v_increment number(4);
begin
  v_empno:=&x;
  select job into v_job from emp where empno=v_empno;
  if v_job = 'CLERK'then v_increment:=100;
  elsif v_job = 'SALESMAN' then v_increment:=160;
  elsif v_job = 'ANALYST' then v_increment:=200;
  else v_increment:=300;
  end if;
  update emp set sal=sal+v_increment where empno=v_empno;
end;

2.case實現

declare
  v_empno emp.empno%type;
  v_job emp.job%type;
  v_increment number(4);
begin
  v_empno:=&x;
  select job into v_job from emp where empno=v_empno;
  case v_job
      when 'CLERK' then v_increment:=100;
      when 'SALESMAN' then v_increment:=160;
      when 'ANALYST' then v_increment:=200;
      else v_increment:=300;
  end case;
  update emp set sal=sal+v_increment where empno=v_empno;
end;

4、迴圈的使用
  1)使用迴圈實現,輸出100以內所有個位上是7的整數(7,17,27...)。

declare
  v_number number(4) := 1;
begin
    loop
       if mod(v_number,10)=7 then
          dbms_output.put_line(v_number);
        end if;
        v_number := v_number + 1;
       exit when v_number >100; 
    end loop;
end;

 2)建立一張包含兩個列的表,使用迴圈向該表新增10行資料,第一列新增從10000開始遞增100的編號,第二列新增字串
'hello world!'。(選做)

create table test1(
    v_num number(6),
    v_text varchar(20)
);
declare
    v_num number(6):=10000;
begin
  loop
    insert into test1 values(v_num,'hello world!');
    v_num := v_num + 100;
    exit when v_num > 11000;
  end loop;
end;

5、遊標的使用
  1)分別用簡單迴圈、WHILE迴圈、FOR迴圈以及顯式遊標統計並輸出各個部門的人數以及平均工資;
1.loop簡單迴圈   

declare
  cursor c_emp is select count(*) c_deptno,avg(sal) c_avgsal from emp group by deptno;
  v_dept c_emp%rowtype;
begin
  open c_emp;
  loop
    fetch c_emp into v_dept;
    exit when c_emp%notfound;
    dbms_output.put_line(v_dept.c_deptno||' '||v_dept.c_avgsal);
  end loop;
  close c_emp;
end;

2.while迴圈

declare
  cursor c_emp is select count(*) c_deptno,avg(sal) c_avgsal from emp group by deptno;
  v_dept c_emp%rowtype;
begin
  open c_emp;
  fetch c_emp into v_dept;
  while c_emp%found loop
    dbms_output.put_line(v_dept.c_deptno||' '||v_dept.c_avgsal);
    fetch c_emp into v_dept;
  end loop;
  close c_emp;
end;

3.for迴圈

declare
  cursor c_emp is select count(*) c_deptno,avg(sal) c_avgsal from emp group by deptno;
begin
  for v_dept in c_emp loop
    dbms_output.put_line(v_dept.c_deptno||' '||v_dept.c_avgsal);
  end loop;
end;

2)使用迴圈和遊標實現,查詢部門編號為10的員工資訊,將查詢結果按照員工編號從大到小的順序排列,輸出倒數第二行
記錄。(選做)

declare
  v_num number(4);
  cursor c_emp is select * from emp where deptno=10 order by empno desc; 
  v_emp c_emp%rowtype;
begin
  select count(*) into v_num from emp where deptno=10 order by empno desc; 
  open c_emp;
  for v_counter in 1..v_num loop
    fetch c_emp into v_emp;
    if v_counter = v_num -1 then 
       dbms_output.put_line(v_emp.empno||' '||v_emp.ename||' '||v_emp.job||' '||v_emp.mgr||' '||v_emp.hiredate||' '||
    v_emp.sal||' '||v_emp.comm||' '||v_emp.deptno);
    end if;
   end loop;
end;

 3)使用隱式遊標實現以下要求:修改部門號為50的部門地址為‘BEIJING’。如果該部門不存在,則向dept表中插入一個部門號為50,
地址為‘BEIJING’的記錄。 (選做)

declare 
begin
    update dept set loc='BEIJING' where deptno=50;
    if sql%notfound then
      insert into dept(deptno,loc) values(50,'BEIJING');
    end if;
end;

6、建立一個顯示僱員總人數的儲存過程emp_count,並執行該儲存過程
建立:

create or replace procedure emp_count
as
  v_count number(4);
begin
  select count(*) into v_count from emp;
  dbms_output.put_line(v_count);
end;

執行:

execute emp_count();

7、編寫顯示僱員資訊的儲存過程EMP_LIST,並引用EMP_COUNT儲存過程
1.建立

create or replace procedure emp_list
as
   cursor emp_list is select * from emp;
begin
   for v_emp in emp_list loop
     dbms_output.put_line(v_emp.empno||' '||v_emp.ename||' '||v_emp.job||' '||v_emp.mgr||' '||v_emp.hiredate||' '||
    v_emp.sal||' '||v_emp.comm||' '||v_emp.deptno);
    end loop;   
end;

2.執行

execute emp_list();

8、建立函式,實現功能為:在scott.emp表和scott.dept表中查詢出任意給定職工號的職工姓名及職工所在部門的名稱。
1.建立

create or replace function emp_dept(
   e_empno emp.empno%type,
   e_name out varchar2)
return dept.dname%type
as
   d_name dept.dname%type;
begin
   select ename,dname into d_name,e_name from emp,dept where emp.empno=e_empno and dept.deptno in 
   (select deptno from emp where empno=e_empno);   
   return d_name;
end  emp_dept;

2.呼叫

declare
   e_empno emp.empno%type;
   d_name dept.dname%type;
   e_name emp.ename%type;
begin
   e_empno:=&x;
   d_name:=emp_dept(e_empno,e_name);
   dbms_output.put_line(e_name||' '||d_name);
end;

9、建立觸發器,實現更新dept表中的deptno值,級聯更新emp表中相應值。

create or replace trigger dept_emp_dml
before update on dept
for each row
begin
   if UPDATING then
      update emp set deptno=:new.deptno where deptno=:old.deptno;
   end if;
end dept_emp_dml;

10、對儲存過程、函式及觸發器實現檢視、修改、刪除等基本操作。

1.對儲存過程的
檢視:select object_name,status from user_objects where object_type='PROCEDURE'; 
修改:CREATE OR REPLACE PROCEDURE procedure_name;
刪除:drop PROCEDURE emp_list;
2.對函式的
檢視:select object_name,status from user_objects where object_type='FUNCTION'; 
修改:CREATE OR REPLACE FUNCTION function_name;
刪除:drop FUNCTION emp_dept;
3.對觸發器的
檢視:select trigger_name,trigger_type,table_name,trigger_body from user_triggers;
修改:CREATE OR REPLACE TRIGGER trigger_name;
刪除:DROP TRIGGER dept_emp_dml; 
end dept_emp_dml;

11、建立一個包mypackage,宣告該包有一個過程update_sal和一個函式get_YearSal
create or replace package mypackage is
    procedure update_sal(name varchar2,newsal number);
    function get_YearSal(name varchar2) return number;
end;
create or replace package body myPackage is
    rprocedure update_sal(name varcha2,newsal number) is
    begin
        update emp set sal=newSal where ename=name;
    end;
  function get_YearSal(name varchar2) return number is
  v_sal number(7,2);
  begin
        select sal*12+nvl(comm,0) into v_sal from emp where ename=name;
        return v_sal;
  end;
  end;
呼叫執行包中的儲存過程或函式

Begin 
  mypackage.update_sql(’smith’,5000);
  mypackage.get_YearSal(’smith’);
end;

12、假設有這樣一張使用者表表結構如下:UserInfo(id ,username,userPass),希望向表中增加資料時,表中id列的數字自動生成。(選做)
1)第一步建立序列,要求開始的數字為1,每次遞增1,按順序產生序列值;

建立表:

Create table UserInfo(
   id number(4),
   username varchar2(20),
   userpass varchar2(20)
);

建立序列:

create sequence UserInfo_Id
increment by 1
start with 1
minvalue 1
maxvalue 999999999;

 更改資料庫的“延遲段建立”特性為false(需要有相應的許可權)

ALTER SYSTEM SET deferred_segment_creation=FALSE; 

測試:

declare 
begin
  for v_counter in 1..10 loop
    insert into UserInfo (id,username,userpass) values(UserInfo_Id.NEXTVAL,'suns','123456');
  end loop;
end;

2)第二步建立一個觸發器,向用戶表中插入資料的時候觸發觸發器,在觸發器內部呼叫序列並生成一個序列值賦值給表的id列。

create or replace trigger userinfo_dml
before insert on UserInfo
for each row
begin
   select UserInfo_Id.nextval into :new.id from dual;
end userinfo_dml;