Oracle實戰練習(續四)

#1.PL/SQL
 #PL/SQL是Oracle內部使用的編程語言, Procedure Language過程語言,其語言格式比較固定
 begin
   dbms_output.put_line('HelloWorld');
 end; 
 /   #/表示執行
 set serveroutput on;   #執行輸出命令,默認是off(關閉)

 declare  #聲明變量
   v_name varchar2(20);
   begin
     v_name := 'myname';    #給變量賦值
     dbms_output.putline(v_name);
   end;
   / 
  #打印:myname, 輸出myname
  #PL/SQL過程已成功完成  
 
 declare
  v_name number:= 0;
 begin
  v_name := 2/v_name;
  dbms_output.put_line(v_name);
  exception
   when others then
    dbms_output.put_line('error');
 end;
 /
 #去掉exception語句塊
 declare
  v_name number:= 0;
 begin
  v_name := 2/v_name;
  dbms_output.put_line(v_name);
 end;
 /
 #則會出現如下錯誤:除數爲 0 在 line 4
 
 #2.變量聲明
     #變量名不能使用保留字,如from, select等
     #第一個字符必須是字母
     #變量名最多包含30個字符
     #不要與數據庫的表或者列同名
     #每一行只能聲明一個變量
 #3.常用變量類型
     #binary_integer: 整數,主要用來計數而不是用來表示字段類型  
     #number : 數字類型
     #char: 定長字符串
     #varchar2: 變長字符串
     #date: 日期
     #long: 長字符串, 最長2GB
     #boolean :布爾類型, 可以取值爲true, false和null值.
    
 declare
   v_temp number(1);
   v_count binary_integer := 0;   --binary_integer 是用來記數的,效率比較高一點.
   v_sal number(7,2) := 4000.00;
   v_date date := sysdate;
   v_pi constant number(3,2) := 3.14;
   v_valid boolean := false;
   v_name varchar2(20) not null := 'MyName';
  begin
   dbms_output.put_line('v_temp value: ' || v_date);
  end;
 
 #4.變量聲明,使用%type屬性
  declare
    v_empno number(4);
    v_empno2 emp.empno%type;  --表示emp表中empno的類型
    v_empno3 v_empno2%type;
   begin
     dbms_output.put_line('Test');
   end; 
 
  --Table 變量類型
  declare
    type type_table_emp_empno is table of emp.empno%type index by binary_integer;
    v_empnos type_table_emp_empno;
   begin
     v_empnos(0):=7369;
     v_empnos(2):=7839;
     v_empnos(-1):= 9999;             
     dbms_output.put_line(v_empnos(-1));
   end; 
  
  --Record變量類型 (相當於java中的類(class))
   declare
     type type_record_dept is record
      (
       deptno dept.deptno%type,
       dname dept.dname%type,
       loc dept.loc%type
      ) ;
     v_temp type_record_dept;  --聲明變量是type_record_dept類型
    begin
      v_temp.deptno :=50;   --引用類型的屬性
      v_temp.dname := 'aaaa';   
       v_temp.loc := 'bj';
       dbms_output.put_line(v_temp.deptno||' '|| v_temp.dname);
    end;
    /
 --record類型是指定義了一個類,然後引用類中的屬性.
 
 --使用%rowtype聲明record變量
 declare
   v_temp dept%rowtype;
 begin
   v_temp.deptno := 50;
   v_temp.dname := 'aaa';
   v_temp.loc := 'bj';
   dbms_output.put_line(v_temp.deptno ||'  ' ||v_temp.dname);
 end;
 /    
 --可以保留原來的類型
 
 --PL/SQL語句,必須返回一條記錄,只能返回一條記錄.
 
 --SQL語句的運用
 declare
   v_ename emp.ename%type;
   v_sal emp.sal%type;
 begin
   select ename, sal into v_ename, v_sal from emp where empno = 7369; --把ename中的記錄賦值給v_ename,sal賦值給v_sal.
   dbms_output.put_line(v_ename ||' '||v_sal);
 end;
 / 
 --結果: SMITH 800
 declare
   v_ename emp.ename%type;
   v_sal emp.sal%type;
 begin
   select ename, sal into v_ename, v_sal from emp where empno = 9999;
   dbms_output.put_line(v_ename ||' '||v_sal);
 end;
 / 
   --如果未找到數據
  
 declare
   v_sal emp.sal%type;
 begin
   select sal into v_sal from emp
      where empno = 7369;
      if(v_sal<1200) then
         dbms_output.put_line('low');
      elsif(v_sal<2000) then
         dbms_output.put_line('middle');
      else
         dbms_output.put_line('high');
      end if;
  end;              
 
  set serveroutput on;
  
  declare
    v_sal2 emp.sal%type;
  begin
     select sal into v_sal2 from emp where empno = 7839;  
      if(v_sal2>2500) then
          v_sal2 := v_sal2 / 2; 
      elsif(v_sal2<2500) then
          v_sal2 := v_sal2 * 2;
      else
          v_sal2 := 2500;  
      end if;
  end;             
  
  --循環
  --loop循環
  declare
    i binary_integer:=1;
  begin
    loop
     dbms_output.put_line(i);
      i := i+1;
      exit when(i>=11);
    end loop;
  end;    
  
  --while循環
 declare
   j binary_integer :=1;
 begin
   while (j<11) loop
    dbms_output.put_line(j);
     j := j +1;
   end loop;
 end; 
 
 --for 循環
 begin
   for k in 1..10 loop
    dbms_output.put_line(k);
   end loop;
   for k in reverse 1..10 loop
    dbms_output.put_line(k);
   end loop;
 end;     
     
 --錯誤處理
 declare
  v_temp number(4);
 begin
  select empno into v_temp from emp where deptno = 10;
 exception
   when too_many_rows then
     dbms_output.put_line('太多記錄');
   when others then
     dbms_output.put_line('error');
 end;  
 
 declare
  v_temp number(4);
 begin
   select empno into v_temp from emp where empno = 2222;
 exception
    when no_data_found then
     dbms_output.put_line('沒數據');
  end;     
     
 --記錄錯誤的做法
  create table errorlog
  (
    id number primary key,
    errcode number,
    errmsg varchar2(1024),
    errdate date
  );  
 
  create sequence seq_errorlog_id start with 1 increment by 1;        
   declare
     v_deptno dept.deptno%type := 10;
     v_errcode number;
     v_errmsg varchar2(1024);
  begin
    delete from dept where deptno = v_deptno;
    commit;
   exception
     when others then
      rollback;
      v_errcode := SQLCODE;
      v_errmsg := SQLERRM;
       insert into errorlog values(seq_errorlog_id.nextval, v_errcode, v_errmsg, sysdate);
     commit;
  end;
            
 select to_char(errdate, 'YYYY_MM_DD HH24:MI:SS') from errorlog;  
 
 --循環定義一個遊標
 --遊標是系統爲用戶開設的一個數據緩衝區,存放SQL語句的執行結果.每個遊標區都有一個名字.
 --用戶可以用SQL語句逐一從遊標中獲取記錄,並賦給主變量,交由主語言進一步處理。主語言是面向記錄的,一組主變量一次只能存放一條記錄。
 declare
   cursor c is
    select * from emp;
    v_emp c%rowtype;
 begin
    open c;
     loop
        fetch c into v_emp;
        exit when(c%notfound);
        dbms_output.put_line(v_emp.ename);
    end loop;
  close c;
 end; 
 
 declare
   cursor c is
    select * from emp;
    v_emp emp%rowtype;
 begin
   open c;
    fetch c into v_emp;
     while(c%found) loop
     dbms_output.put_line(v_emp.ename);
      fetch c into v_emp;
     end loop;
   close c;
  end;    
    
 --帶參數的遊標
 declare
  cursor c (v_deptno emp.deptno%type, v_job emp.job%type) is
   select ename, sal from emp where deptno=v_deptno and job= v_job;
   --v_temp(%rowtype)
 begin
   for v_temp in c(30,'CLEAK') loop
   dbms_output.put_line(v_temp.ename);
  end loop;
end;    
         
 --可更新的遊標
 declare
    cursor c is
       select * from emp2 for update;
  begin
    for v_temp in c loop
     if(v_temp.sal<2000)then
      update emp2 set sal= sal*2 where current of c; --更新當前遊標,遊標到哪條記錄,更新哪條.
     elsif(v_temp.sal = 5000) then
      delete from emp2 where current of c;
     end if;
    end loop;
  commit;
 end;    
 
 --存儲過程
 --(帶有名字的PL/SQL的程序塊)
 create or replace procedure p 
   is
     cursor c is
      select * from emp2 for update;
  begin
    for v_emp in c loop
      if(v_emp.deptno = 10) then
        update emp2 set sal= sal+10 where current of c;
      elsif(v_emp.deptno =20) then
        update emp2 set sal=sal+20 where current of c;
      else 
        update emp2 set sal=sal+30 where current of c ;
      end if;
    end loop;
  end;  
 --執行存儲過程
 exec p;
 --查看結果集
 select sal from emp2;
 --或者
 begin p;
 end;
 --再執行了一次
 --查看結果集
 select sal from emp2;
 
 --帶參數的存儲過程
 create or replace procedure p1
  (v_a in number, v_b number, v_ret out number, v_temp in out number)
   is
    begin
      if(v_a>v_b) then
        v_ret :=v_a;
      else
        v_ret :=v_b;
      end if;
      v_temp:=v_temp+1;
    end;
 --調用過程
 declare
   v_a number :=3;
   v_b number :=4;
   v_ret number;
   v_temp number:=5;
 begin
   p(v_a, v_b, v_ret, v_temp);
   dbms_output.put_line(v_ret);
   dbms_output.put_line(v_temp);
 end; 
 --結果
 4
 6
 
 --刪除存儲過程
  drop procedure p;
 show error;   --顯示錯誤.
 
 --函數(function)
 create or replace function sal_tax
   (v_sal number) return number
    is
    begin
      if(v_sal<2000)then
        return 0.10;
      elsif(v_sal<2750) then
        return 0.15;
      else
       return 0.20;
      end if;
    end;         
  -- 運用函數
  select lower(ename), sal_tax(sal) from emp;
 
  --觸發器
  create table emp2_log
    (
      aname varchar2(20),
      action varchar2(10),
      atime date
     );
    
  create or replace trigger trig
    after insert or delete or update on emp2 for each row
   begin
     if inserting then
      insert into emp2_log values(USER,'insert',sysdate);
     elsif updating then
       insert into emp2_log values(USER,'update',sysdate);
     elsif deleting then
       insert into emp2_log values(USER,'delete',sysdate);
    end if;
  end;           
   
 update emp2 set sal= sal*2 where deptno=30;
 select * from emp2_log;
 update dept set deptno = 99 where deptno=10;#違反完整約束條件 (DYS.FK_DEPTNO),因爲有外鍵參考.
 
 --刪除觸發器
 drop trigger trig;
 
 create or replace trigger trig
   after update on dept
     for each row
  begin
     update emp set deptno=:NEW.deptno where deptno=:OLD.deptno;
 end;    
 
  update dept set deptno=99 where deptno=10;
  select deptno from dept;
 
--樹狀結構的存儲與展示
  drop table article;
  create table article
   (
     id number primary key,
     cont varchar2(4000),
     pid number,
     isleaf number(1),--0代表非葉子節點,1代表葉子節點.
     alevel number(2)
   ); 
  
  insert into article values(1,'螞蟻大戰大象',0,0,0);
  insert into article values(2,'大象被打趴下了',1,0,0);
  insert into article values(3,'螞蟻也不好過',2,1,2);
  insert into article values(4,'瞎說',2,0,2);
  insert into article values(5,'沒有瞎說',4,1,3);
  insert into article values(6,'怎麼可能',1,0,1);
  insert into article values(7,'怎麼沒有可能',6,1,2);
  insert into article values(8,'可能性是很大的',6,1,2);
  insert into article values(9,'大象進醫院了',2,0,2);
  insert into article values(10,'護士是螞蟻',9,1,3);
 
  create or replace procedure p1(v_pid article.pid%type, v_level binary_integer)  is
    cursor c is select * from article where pid=v_pid;
   begin
     for v_article in c loop
       dbms_output.put_line(v_article.cont);
     
   
         
                                

發佈了61 篇原創文章 · 獲贊 9 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章