create or replace package pack1

is

 TYPE emp_rec_tab_type IS TABLE OF emp%rowtype

   INDEX BY PLS_INTEGER;

end;

/


create or replace procedure up_emp_sawon_all (

   p_emp_all out pack1.emp_rec_tab_type

)

is

begin

 select * bulk collect into p_emp_all

 from emp;

end;

/


  ----------

  > 활용 1 <

  ----------

  

declare

 r pack1.emp_rec_tab_type;

begin

 up_emp_sawon_all(r);


 for i in r.first .. r.last loop

   p(r(i).empno||' '||r(i).ename||' '||r(i).job||' '||r(i).sal);

 end loop;

end;

/

'Oracle > PL/SQL' 카테고리의 다른 글

15일차 # 문제  (0) 2012.04.24
15일차 # 1-13  (0) 2012.04.24
15일차 # 1-10  (0) 2012.04.24
15일차 # 1-6  (0) 2012.04.24
15일차 PL/SQL Program Unit Chapter 1 - Procedures  (0) 2012.04.24

        create or replace procedure up_emp_sawon (

   p_empno   in  emp.empno%type

 , p_emp_rec out emp%rowtype

)

is

begin

 select * into p_emp_rec 

 from emp

 where empno = p_empno;

end;

/

  

  ----------

  > 활용 1 <

  ----------


declare

 emp_rec emp%rowtype;

begin

 up_emp_sawon(7788, emp_rec);

 p(emp_rec.ename);

 p(emp_rec.sal);

end;

/


  ----------

  > 활용 2 <

  ----------


declare

 emp_rec emp%rowtype;

begin

 for r in (select empno from emp) loop

   up_emp_sawon(r.empno, emp_rec);

   p(emp_rec.ename||' '||emp_rec.job||' '||emp_rec.sal);

 end loop;

end;

/

'Oracle > PL/SQL' 카테고리의 다른 글

15일차 # 1-13  (0) 2012.04.24
15일차 # 1-11  (0) 2012.04.24
15일차 # 1-6  (0) 2012.04.24
15일차 PL/SQL Program Unit Chapter 1 - Procedures  (0) 2012.04.24
15일차 # 8-22: [5] RAISE_APPLICATION_ERROR 프로시져  (0) 2012.04.24

        create or replace procedure up_emp_ename_sal (

   a in  emp.empno%type

 , b out emp.ename%type

 , c out emp.sal%type

)

is

begin

 select ename, sal into b, c

 from emp

 where empno = a;

end;

/


  --------------

  > 사용방법 1 <

  --------------


var g_empno number

exec :g_empno := 7788


var g_ename varchar2(30)

var g_sal   number


exec up_emp_ename_sal(:g_empno, :g_ename, :g_sal)                  --> positional

print g_ename g_sal


exec up_emp_ename_sal(a => :g_empno, c => :g_sal, b => :g_ename)   --> named

print g_ename g_sal


exec up_emp_ename_sal(:g_empno, c => :g_sal, b => :g_ename)        --> combination

print g_ename g_sal


  --------------

  > 사용방법 2 <

  --------------


set serveroutput on


declare

 v_ename emp.ename%type;

 v_sal   emp.sal%type;

begin

 up_emp_ename_sal(7788, v_ename, v_sal);

 p(v_ename);

 p(v_sal);

end;

/


'Oracle > PL/SQL' 카테고리의 다른 글

15일차 # 1-11  (0) 2012.04.24
15일차 # 1-10  (0) 2012.04.24
15일차 PL/SQL Program Unit Chapter 1 - Procedures  (0) 2012.04.24
15일차 # 8-22: [5] RAISE_APPLICATION_ERROR 프로시져  (0) 2012.04.24
15일차 # 8-18: [4] define  (0) 2012.04.24

  Parameters


  * Pass or communicate data between the CALLER and the CALLEE (subprogram)



  * Used like local variables to the named blocks



  * formal parameter vs actual parameter

    - formal parameter : parameter passing mode (in, out, in out)

    - actual parameter : passing Parameters (positional, named, combination)

'Oracle > PL/SQL' 카테고리의 다른 글

15일차 # 1-10  (0) 2012.04.24
15일차 # 1-6  (0) 2012.04.24
15일차 # 8-22: [5] RAISE_APPLICATION_ERROR 프로시져  (0) 2012.04.24
15일차 # 8-18: [4] define  (0) 2012.04.24
15일차 # 8-16: [3] when others then  (0) 2012.04.24

        create or replace procedure up_exceptions5(a number)

is 

 v_sal number;

begin

 select sal into v_sal

 from emp

 where empno = a;


 if v_sal < 1000 then

   RAISE_APPLICATION_ERROR('-20001', '급여가 너무 적사옵니다, 주인님!');

 end if;

   

  p('잘 처리되었사옵니다, 주인님!');

end;

/


exec up_exceptions5(7369)      --> 에러: ORA-20001: 급여가 너무 적사옵니다, 주인님!


↓ ↓ ↓ 


create or replace procedure up_exceptions5(a number)

is 

 v_sal number;

 e_too_small exception;

 pragma exception_init(e_too_small, -20001);

begin

 select sal into v_sal

 from emp

 where empno = a;


 if v_sal < 1000 then

   RAISE_APPLICATION_ERROR('-20001', '급여가 너무 적사옵니다, 주인님!');

 end if;

  

  p('잘 처리되었사옵니다, 주인님!');

exception

 when e_too_small then

   p('기본 급여가 너무 적사옵니다, 주인님!');

end;

/


exec up_exceptions5(7369) 




# 문제


drop table t1 purge;

create table t1 (no number primary key);

insert into t1 values (1000);

commit;


create or replace procedure up_exception_test(a number)

is

begin

 insert into t1 values (a);

end;


exec up_exception_test(1000)



[2] 방법으로 exception 처리


create or replace procedure up_exception_test(a number)

is

 예외 변수 선언;

 예외 변수를 예외 코드와 연결;

begin

 insert into t1 values (a);

exception

 when 예외 변수 then

   p('컬럼의 primary key 제약 조건을 위배하셨사옵니다, 주인님!');

end;


exec up_exception_test(1000);



[3] 방법으로 exception 처리


create or replace procedure up_exception_test(a number)

is

begin

 insert into t1 values (a);

exception

 when others then

   p('알 수 없는 예외가 발생하였사옵니다, 주인님!');

   p('예외 코드는 ' || sqlcode || '이옵고,');

   p('예외 메시지는 ' || sqlerrm || '이옵나이다.');

end;


exec up_exception_test(1000);


    define => raise => when 이름 then


create or replace procedure up_exceptions4(a number)

is 

 v_sal       emp.sal%type;

 e_too_small exception; -- define exception

begin

 select sal into v_sal

 from emp

 where empno = a;


 if v_sal < 1000 then

   raise e_too_small; -- raise exception

 end if;

   

 p('잘 처리되었사옵니다, 주인님!');

end;

/


exec up_exceptions4(7788)

exec up_exceptions4(7369)      --> 에러: ORA-06510: PL/SQL: 처리되지 않은 user-defined 예외 상황


  ↓ ↓ ↓ 


create or replace procedure up_exceptions4(a number)

is 

 v_sal       emp.sal%type;

 e_too_small exception; -- define exception

begin

 select sal into v_sal

 from emp

 where empno = a;


 if v_sal < 1000 then

   raise e_too_small; -- raise exception

 end if;

   

 p('잘 처리되었사옵니다, 주인님!');


 /*

 ... 여러 실행문 ...

 ... 여러 실행문 ...

 */

exception

 when e_too_small then -- trap exception

   p('기본 급여가 너무 적사옵니다, 주인님!');

end;

/


exec up_exceptions4(7788)

exec up_exceptions4(7369)


        drop table t1 purge;

create table t1 (no number not null);


create or replace procedure up_exceptions3(a number)

is 

begin

 insert into t1 values (a);    

end;

/


exec up_exceptions3(100) 

exec up_exceptions3(null)      --> 에러: ORA-01400: NULL을 ("TOP20"."T1"."NO") 안에 삽입할 수 없습니다


  ↓ ↓ ↓ 


create or replace procedure up_exceptions3(a number)

is 

begin

 insert into t1 values (a);  

exception

 when others then

   p('알 수 없는 문제가 발생하였사옵니다, 주인님!');

   p(sqlcode);

   p(sqlerrm);

end;

/


exec up_exceptions3(null)


  * 이름 부여: 

1) 선언부에서 exceptino type의 exception 변수를 선언

: 이 변수가 exception 이름이 됩니다.


2) 선언부에서 PRAGMA EXCEPTION_INIT(Exception 이름(변수), -에러 번호)



drop table t1 purge;

create table t1 (no number not null);


create or replace procedure up_exceptions2(a number)

is 

begin

 insert into t1 values (a);    

end;

/


exec up_exceptions2(100) --> 정상 처리

exec up_exceptions2(null) --> 에러: ORA-01400: NULL을 ("TOP20"."T1"."NO") 안에 삽입할 수 없습니다


↓ ↓ ↓ 


create or replace procedure up_exceptions2(a number)

is 

 e_null exception;

 pragma exception_init(e_null, -1400);

begin

 insert into t1 values (a); 

exception

 when e_null then

   p('널 값을 입력하시면 아니되옵니다, 주인님!');   

end;

/


exec up_exceptions2(null) 


'Oracle > PL/SQL' 카테고리의 다른 글

15일차 # 8-18: [4] define  (0) 2012.04.24
15일차 # 8-16: [3] when others then  (0) 2012.04.24
15일차 # 8-11: [1] when 이름 then  (0) 2012.04.24
15일차 # 8-21: Exception Propagation  (0) 2012.04.24
15일차 # 8-5: 예외 처리  (0) 2012.04.24

        create or replace procedure up_exceptions1(a number, b number)

is 

 v_ret number;

begin

 v_ret := a/b;

 p(v_ret);

end;

/


exec up_exceptions1(100, 10)   --> 정상 처리

exec up_exceptions1(100, 0)    --> 에러: ORA-01476: 제수가 0 입니다


↓ ↓ ↓ 


create or replace procedure up_exceptions1(a number, b number)

is 

 v_ret number;

begin

 v_ret := a/b;

 p(v_ret);

exception

 when ZERO_DIVIDE then

   p('주인님, 0으로 나누시면 안되옵나이다.');

end;

/


exec up_exceptions1(100, 10) 

exec up_exceptions1(100, 0) 


참고 : http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/errors.htm#i3365



  * To reraise an exception, use a RAISE statement without an exception name


  * An exception raised in a declaration propagates immediately to the enclosing block.


  * An exception raised inside a handler propagates immediately to the enclosing block.

 * Exception = PL/SQL error


    - is raised ┌ implicitly (by Oracle server)

└ explicitly (by Program)

    - is handled┌ trapping (직접 처리)  --> 핸들러에 의해

└ propagating (떠넘기기)


  * 8-6 그림 참조



  * Exception Handler: WHEN + Exception name + THEN + Statements

      - Every Oracle error has a number,

        but exceptions must be handled by name.


      - WHEN OTHERS exception handler

. must be the last exception handler




# Exception이 처리되고 나면


  - 기본: Tx is rolled back.

  

  - 예외처리부에서 명시적으로 commit, rollback 문을 사용하여 트랜잭션을 종료할 수도 있음




참고:http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/static.htm#sthref652


 * current of를 사용하려면 커서가 for update와 함께 선언되어야 함

--> FOR UPDATE cursor


  * without need to explicitly reference the row ID

- Simulating CURRENT OF Clause with ROWID Pseudocolumn: http://goo.gl/io8Wq



  * simulation


drop table test_emp purge;

create table test_emp as select * from emp;

create index test_emp_empno_idx on test_emp(empno);


begin

 for i in 1..10 loop

   insert into test_emp select * from test_emp;

 end loop;

 commit;

end;

/  


select count(*) from test_emp;


   ------------------------------


  1> UNIQUE KEY


create or replace procedure test_emp_sal_update_proc1(p_deptno number, p_percent number)

is

 cursor emp_cur(dno number) is

   select * from test_emp

   where deptno = dno

   FOR UPDATE;

begin

 for r in emp_cur(p_deptno) loop

   update test_emp

   set sal = r.sal*p_percent

   where empno = r.empno;

 end loop;

end;

/


   ------------------------------


  2> ROWID


create or replace procedure test_emp_sal_update_proc2(p_deptno number, p_percent number)

is

 cursor emp_cur(dno number) is

   select ROWID as id, e.* --> ROWID 추가

   from test_emp e

   where deptno = dno

   FOR UPDATE;

begin

 for r in emp_cur(p_deptno) loop

   update test_emp

   set sal = r.sal*p_percent

   where ROWID = r.id; --> WHERE 절에서 ROWID 사용

 end loop;

end;

/


   ------------------------------


  3> CURRENT OF

create or replace procedure test_emp_sal_update_proc3(p_deptno number, p_percent number)

is

 cursor emp_cur (dno number) is

   select * 

   from test_emp

   where deptno = dno

   FOR UPDATE;

begin

 for r in emp_cur(p_deptno) loop

   update test_emp

   set sal = r.sal*p_percent

   where CURRENT OF emp_cur; --> CURRENT OF 절

 end loop;

end;

/


   ------------------------------


set timing on


exec test_emp_sal_update_proc1(10, 1.2)      --> Elapsed: 00:00:31.65

rollback;


exec test_emp_sal_update_proc2(10, 1.2)      --> Elapsed: 00:00:00.39

rollback;


exec test_emp_sal_update_proc3(10, 1.2)      --> Elapsed: 00:00:00.28

rollback;


   ------------------------------


  * NOWAIT


[session 1] [session 2]

----------- -----------


drop table emp_test purge;


create table emp_test

        as 

select empno, ename, job, sal, deptno 

from emp;

select * from emp_test;


select * from emp_test;


declare

 cursor cur_emp is

   select *

   from emp_test FOR UPDATE;


 rec_emp cur_emp%rowtype;


begin

 open cur_emp;


 loop  

   fetch cur_emp into rec_emp;

   exit when cur_emp%notfound;


   if rec_emp.job = 'CLERK' then

     update emp_test

     set sal = sal * 1.1

     where current of cur_emp;

   end if;

 end loop;


 close cur_emp;

end;

/


select * from emp_test;


update emp_test

set deptno = 40

where ename like 'S%';


commit;

select * from emp_test;


select * from emp_test;

rollback;


   ------------------------------------------------------------


[session 1] [session 2]

----------- -----------


drop table emp_test purge;


create table emp_test

        as 

select empno, ename, job, sal, deptno 

from emp;


select * from emp_test;


update emp_test

set deptno = 40

where ename like 'S%';


declare

 cursor cur_emp is

   select *

   from emp_test for update NOWAIT; --> nowait 추가


 rec_emp cur_emp%rowtype;


begin

 open cur_emp;


 loop  

   fetch cur_emp into rec_emp;

   exit when cur_emp%notfound;


   if rec_emp.job = 'CLERK' then

     update emp_test

     set sal = sal * 1.1

     where current of cur_emp;

   end if;

 end loop;


 close cur_emp;

end;

/

==> 에러: ORA-00054: 리소스가 사용 중이어서 NOWAIT가 지정되었거나 시간 초과가 만료된 상태로 획득합니다.

<-- session 2에서 SMITH와 SCOTT의 행에 LOCK을 걸었기 때문



commit;

/


select * from emp_test;


SELECT ... FOR UPDATE [OF 컬럼] [NOWAIT|WAIT n]


  - active set의 row들에 명시적으로 lock을 걸어 

    다른 세션이 동일 row를 수정, 삭제하는 것을 막고자 할 때 사용

    


  * SQL 문에서 select ... for update


[session 1] [session 2]

----------- -----------


SQL> select * from emp

 2  where empno = 7788;

SQL> update emp

 2  set sal = sal*1.1

 3  where empno = 7788;


1 행이 갱신되었습니다.

SQL> select * from emp

 2  where empno = 7900

 3  for update;

SQL> update emp

 2  set sal = sal*1.5

 3  where empno = 7900;

--> 대기중

SQL> rollback;

1 행이 갱신되었습니다.


SQL> rollback;


SQL>  update emp

 2   set sal = sal*1.1

 3   where empno = 7788;


1 행이 갱신되었습니다.

SQL> select * from emp

 2  where empno = 7788

 3  for update wait 10;

==> 오류: ORA-30006: 리소스 사용 중. WAIT 시간 초과로 획득이 만료됨


SQL> select * from emp

 2  where empno = 7788

 3  for update nowait;

==> 오류: ORA-00054: 리소스가 사용 중이어서 NOWAIT가 지정되었거나 시간 초과가 만료된 상태로 획득합니다.


프로시저에 적용


- 부서 번호를 입력 받아 해당 부서 사원의 

 사원번호, 이름, 급여 출력하는 프로시저



    1) Subprogram + Cursor For Loop with Parameters


create or replace procedure list_emp(a number)

is

 cursor emp_cur (dno number) is

   select * from emp

   where deptno = dno

   order by sal desc;

begin

 for r in emp_cur(a) loop

   p(r.empno||' '||r.ename||' '||r.sal);       

 end loop;

end;

/



exec list_emp(10)

exec list_emp(30)

exec list_emp(90)


   ------------------------------


    2) Subprogram + Cursor For Loop with Parameters + 없는 값 조사

   

create or replace procedure list_emp(a number)

is

 cursor emp_cur (dno number) is

   select * from emp

   where deptno = dno

   order by sal desc;

 flag number := 0;


begin

 for r in emp_cur(a) loop

   p(r.empno||' '||r.ename||' '||r.sal);       

   flag := flag + 1;

 end loop;


 if flag = 0 then

   p('존재하지 않는 부서이옵니다, 주인님!');

 end if;

end;

/



exec list_emp(30)

exec list_emp(90)


   ------------------------------


    3) Subprogram + Cursor with Parameters + 없는 값 조사


create or replace procedure list_emp(a number)

is

 cursor emp_cur (dno number) is

   select * from emp

   where deptno = dno

   order by sal desc;

 r emp_cur%rowtype;

begin

 

 open emp_cur(a);


 loop

   fetch emp_cur into r;


   if emp_cur%notfound and emp_cur%rowcount=0 then

     p('존재하지 않는 부서이옵니다, 주인님!');

     exit;

   end if;


   exit when emp_cur%notfound;

   p(r.empno||' '||r.ename||' '||r.sal);      


 end loop;

end;

/


exec list_emp(30)

exec list_emp(90)


   ------------------------------


  4) 위와 동일한 결과가 나타나되 전혀 다른 방법으로 구현.

(Associative array, BULK COLLECT, Exception section)



create or replace procedure list_emp(a number)

is

 TYPE emp_table_type IS TABLE OF emp%rowtype

   INDEX BY PLS_INTEGER;

  

 r emp_table_type;

begin

 select * bulk collect into r

 from emp

 where deptno = a

 order by sal desc;


 for i in r.first .. r.last loop

   p(r(i).empno||' '||r(i).ename||' '||r(i).sal); 

 end loop;


exception

 when others then

   p('존재하지 않는 부서이옵니다, 주인님!');

end;

/



exec list_emp(30)

exec list_emp(90)



+ Recent posts