PL/SQL

MisCaminos·2021년 2월 3일
0

DBMS

목록 보기
4/6
post-thumbnail

1. PL/SQL작성법

복잡한 구조의 질의를 하려고, 관련있는 동작을 연속으로 실행하여
결과를 변수에 담거나 출력할 수 있다

-3종류 구문이 있음
DECLARE //변수 선언
BEGIN //실행하는 부분
EXCEPTION //예외발생 시 실행하는 부분

example)

declare //변수선언
   vename employees.last_name%type;
   vempno employees.employee_id%type;
   vjob_id employees.job_id%type;
   vdeptname departments.department_name%type;
begin //현재 실행하고싶은 부분
   select employee_id, last_name, job_id, department_name
   into vempno, vename, vjob_id, vdeptname
   from employees e, departments d
   where e.department_id=d.department_id
   and employee_id=145;
   DBMS_OUTPUT.PUT_LINE('emp no:' ||  vempno);
   DBMS_OUTPUT.PUT_LINE('name:' ||  vename);
   DBMS_OUTPUT.PUT_LINE('job:' ||  vjob_id);
   DBMS_OUTPUT.PUT_LINE('department:' ||  vdeptname);
end;

-제어문(프로그램의 흐름을 제어) & 선택문(조건에 따른 실행내용 선택)
1) if(조건) then ~ end if
example)

declare
   vscore number(3);
begin
   vscore := 50;
   if(vscore>=60)
   then DBMS_OUTPUT.PUT_LINE('합격');
   end if;
   end;

2) if(조건) then ~ else ~end if

declare
   vscore number(3);
begin
   vscore := 50;
   if(vscore>=60)
   then DBMS_OUTPUT.PUT_LINE('합격');
   else DBMS_OUTPUT.PUT_LINE('불합격');
   end if;
   end;
   /

3) if(조건1) then ~ elsif(조건2) ~ else~end if

declare
   x number(1);
begin
   x := 3;
   if(x=1)
   then DBMS_OUTPUT.PUT_LINE('하나');
   elsif(x=2) 
   then DBMS_OUTPUT.PUT_LINE('둘');
   elsif(x=3) 
   then DBMS_OUTPUT.PUT_LINE('셋');
   elsif(x=4) 
   then DBMS_OUTPUT.PUT_LINE('넷');
   else
   DBMS_OUTPUT.PUT_LINE('범위 밖의 값');
   end if;
   DBMS_OUTPUT.PUT_LINE('if밖');
   end;
   /

-반복문
1)loop
example)

declare
        x number :=1;
        y number :=0;
    begin
        loop
            y:=y+x;
            x:=x+1;
            if(x>100)
                then exit;
            end if;
        end loop;
        DBMS_OUTPUT.PUT_LINE(y);
    end;
    /

2)forloop
example)

declare
        dan number(1);
        x number:=1;
    begin
        dan:=&dan;        
        for x in 1..9 loop
            DBMS_OUTPUT.PUT_LINE(dan || ' * ' || x || ' = ' || dan*x);
        end loop; 
    end;
    / 

3) while loop
example)

declare
    x number:=1;
begin
    while x<10 loop
        DBMS_OUTPUT.PUT_LINE(x);
        x:=x+1;
    end loop;
end;

-테이블 타입(여러줄을 담을 수 있는 타입)
1)타입정의
type 타입명 is table of 테이블명.컬럼명%type
index by binary_integer;
2)정의한 타입으로 변수 선언
3)루프를 돌며 값을 하나씩 꺼내어 사용

example)

declare
    type ename_arr is table of employees.last_name%type
    index by binary_integer;
    type job_arr is table of employees.job_id%type
    index by binary_integer;
    
    names ename_arr;
    jobs job_arr;
    
    i binary_integer:=0; 
begin
    for k in(select last_name, job_id from employees) loop
        i:=i+1;
        names(i):=k.last_name;
        jobs(i):=k.job_id;
    end loop;
    
    for j in 1..i loop
        DBMS_OUTPUT.PUT_LINE(names(j) || ' / ' || jobs(j));
    end loop;
end;

-레코드 타입
%rowtype은 지정한 테이블의 모든 컬럼을 포함
record 타입은 지정한 테이블의 원하는 컴럼만 포함

타입 정의: type 타입명 is record(컬럼 리스트);
==>컬럼 리스트는 컬럼명 타입으로 정의

example)

declare
    type emp_record is record(
    vnum employees.employee_id%type,
    vname employees.last_name%type,
    vsalary employees.salary%type,
    vjob employees.job_id%type);
    
    vemp_rec emp_record;
begin
    select employee_id, last_name, salary, job_id
    into vemp_rec 
    from employees
    where employee_id=100;
    DBMS_OUTPUT.PUT_LINE(vemp_rec.vnum || ' / ' || 
    vemp_rec.vsalary || ' / ' || vemp_rec.vjob || ' / ' || 
    vemp_rec.vname);
end;
/

2. Procedure

(주의사항:
set serveroutput on;
위 문장을 실행해야 프로시져, 함수 등 안에 구현해둔 print문 확인가능)

procedure을 사용하는 목적

sql file에 작성해서 저장해놓은 여러 라인의 SQL문장을 block설정해서 실행할 수도 있지만
필요할때마다 or 프로그램 내 코드 사이에 호출해서 하기는 어렵다.

procedure로 저장해두면
(java에서 method 호출하듯이) procedure을 필요할때에 호출해서 사용할 수 있음.

실행방법

exec로 호출하되,
in, out parameter는 실행하는 환경에서 변수 선언 및 주어져야함.

example)

create or replace PROCEDURE PROC1 
(
  EMP_ID IN EMPLOYEES.EMPLOYEE_ID%TYPE,
  emp_name out employees.last_name%type,
  emp_salary out employees.salary%type
) AS 
BEGIN
  select last_name, salary into emp_name, emp_salary 
  from employees 
  where employee_id=emp_id;
END PROC1;

실행 example)

var emp_name varchar2(25);
var emp_salary number;
exec proc1(206, :emp_name, :emp_salary); 
/*procedure_name(input 변수; :반환받을 변수1,:반환받을 변수2))*/
print emp_name;
print emp_salary;

여기서 변수 앞에 : 는 binding을 의미한다.
반환 받는 값을 외부에서도 사용 할 수 있도록 지정하는 목적.

procedure을 통해 얻을 수 있는 OUT paramter는 여러 행을 포함하는 형태를 가질 수 있다 <-- cursor을 사용하면 가능!

cursor는 JDBC의 ResultSet과 동일한 역할을 한다. 여러줄의 검색결과가 cursor객체에 들어가고, cursur를 통해 결과를 가져올 수 있다.

example)

create or replace PROCEDURE PRODUCT_LIST AS 
    cursor c is select * from product order by sno; 
    r product%rowtype; 
    /*product테이블의 한줄을 담을 수 있는 type */
BEGIN
  open c; 
  /*cursor open한 후 사용*/
    loop
        fetch c into r; 
        /*c 한개씩 fetch해서 r에 담아라*/
        exit when c%NOTFOUND; 
        /*더이상 c에서 읽을것이 없을때 exit*/
        DBMS_OUTPUT.PUT_LINE('sno:'||r.sno||'/name:'||
                r.name||'/company:'||r.company||'/p_date:'||r.p_date||
                '/price:'||r.price||'/quantity:'||r.quantity);
    end loop;
    close c; 
    /*cursor 사용완료 후 close*/
END PRODUCT_LIST;

실행 example)

exec product_list(); 

3. Function (함수)

함수를 사용하는 목적
SQL의 내장함수 (MIN, AVG, MAX, etc)와 같은 함수들대신
내가 직접 함수를 구현해서 사용하는 것.

실행방법
exec로 호출할수도 있고,
또는 SQL query문 안에서 함수자체를(반환되는 값을) 사용할 수 있음.

실행 example - query문 안에서 호출)

select make_name(first_name, last_name) name
from employees;

실행 example- exec로 호출)

exec get_product_by_name('신라면');

아래 예시와 같이 exception문구를 작성하여, 예외가 발생하여도 함수가 항상 값을 반환한다.

create or replace FUNCTION MAKE_GRADE 
(
  SCORE IN NUMBER 
) RETURN VARCHAR2 AS 
    grade varchar2(20):='잘못된 점수';
    score_range_exception exception;
BEGIN
    if(score>100 or score < 0)
        then raise score_range_exception;--예외를 강제로 발생
        else 
            if(score>=90) then grade:='A';
            elsif(score>=80) then grade:='B';
            elsif(score>=70) then grade:='C';
            elsif(score>=60) then grade:='D';
            else grade:='F';
            end if;
    end if;
    RETURN grade;
    exception 
        when score_range_exception 
            then DBMS_OUTPUT.PUT_LINE('score_range_exception 발생'); 
                    RETURN grade;
END MAKE_GRADE;

4. Trigger

TRIGGER 사용 목적
테이블에 사건 발생 전/후 상태를 저장/관리

실행방법
사건이 발생한 이력을 담을 테이블A를 생성하고
다른 테이블B에 사건이 발생하면 (insert, update, delete)
trigger내 구현문안에서 정의한대로 테이블A에 사건 이력이 담긴다.
trigger는 사건 before/after로 두종류가 있음

example)

CREATE OR REPLACE TRIGGER TRIGGER1 
after DELETE OR INSERT OR UPDATE /*after:사건(delete,insert,update) 발생 후 */
ON emp
for each row
BEGIN /*사건의 종류별 실행 사항 나열*/
/*여기 쓰이는 old(사건 전), new(사건 후)는 정해진 binding keyword*/
  if inserting then insert into emp_tmp 
    values(:new.employee_id, :new.last_name, :new.job_id,
    :new.salary, 'i'); /*마지막은 동작 종류*/
  elsif updating then insert into emp_tmp 
    values(:old.employee_id, :old.last_name, :old.job_id,
    :old.salary, 'u');
  elsif deleting then insert into emp_tmp 
    values(:old.employee_id, :old.last_name, :old.job_id,
    :old.salary, 'd');
  end if;
END;

실행 example)

create table emp_temp 
as select employee_id, last_name, job_id, salary
from employees where 1=0;

alter table emp_temp
add (action varchar2(1));

insert into emp values(206, 'aaa', 'bbb', 'emaila', '111.222.3333', 
sysdate, 'MK_MAN', 13000, null, 100, 20);

update emp set salary=15000 where employee_id=206;
delete emp where employee_id=206;

select * from emp_temp;
profile
Learning to code and analyze data

0개의 댓글