본문 바로가기
국비교육

1월 28일 국비교육

by Diligejy 2019. 1. 28.

#1

p.353 예제 안되므로 여쭤볼 것.


#2

PL/SQL 복습


1. 

DECLARE 선언부 - 옵션


BEGIN 실행부 - 필수 


EXCEPTION - 예외처리부 - 옵션


END


2. 

쿼리문을 수행하기 위해서 ' / ' 가 반드시 입력되어야 하며, PL/SQL 블록은 행에 ' / '가 있으면 종결된 것으로 간주.

#2

커서


1. SELECT 문의 수행 결과가 여러 개의 로우로 구해지는 경우에 모든 로우에 대해 처리를 하려면 커서를 사용해야 합니다.


2. 커서는 CURSOR, OPEN, FETCH, CLOSE 4단계 명령에 의해 사용됩니다.


3. 키워드 CURSOR 뒤에 커서의 이름을 기술하고 IS 뒤에 커서 내에서 수행할 SELECT 문을 정의합니다. SELECT 문장에는 INTO 절을 포함하지 않아야 합니다.


4. CURSOR FOR LOOP는 명시적 CURSOR에서 로우를 처리합니다. CURSOR가 내부적으로 OPEN되고, FETCH되고 나서 CLOSE되기 때문에 OPEN ~ FETCH ~ CLOSE 과정 없이 DECLARE 절에서 선언만하고 바로 사용할 수 있어 간편합니다. CURSOR의 데이터를 읽어와서 저장할 변수도 따로 선언할 필요가 없습니다.


5.

만들어진 stored procedure list 보기

-- select * from user_procedures;


프로시저의 내용까지 확인


6.

SQL> CREATE OR REPLACE PROCEDURE EMP_EX01

  2  IS

  3  V_EMPNO EMP.EMPNO%TYPE; --변수 선언

  4  V_ENAME EMP.ENAME%TYPE;

  5   V_SAL NUMBER(7, 2);

  6  CURSOR EMP_CURSOR IS -- 1. 커서 선언 : 하나 이상의 ROW를 담을 객체

  7  SELECT EMPNO, ENAME, SAL FROM EMP

  8  WHERE DEPTNO = 20;

  9  BEGIN -- 실제 실행 코드

 10  OPEN EMP_CURSOR; --2. 커서 시작

 11  LOOP -- 한 줄 이상 대입변수 출력, LOOP 구문 사용

 12  FETCH EMP_CURSOR INTO V_EMPNO, V_ENAME, V_SAL; --3. 변수를 대입

 13  EXIT WHEN EMP_CURSOR%ROWCOUNT > 5 OR EMP_CURSOR%NOTFOUND;

 14  DBMS_OUTPUT.PUT_LINE(V_EMPNO||'   '||V_ENAME||'   '||V_SAL);

 15  END LOOP;

 16  CLOSE EMP_CURSOR;

 17  END EMP_EX01;

 18  /


7. 사원 테이블에서 사원의 이름과 봉급을 출력해보자.
SQL> CREATE OR REPLACE PROCEDURE EX_VIEW
  2  IS
  3     R_ENAME EMP.ENAME%TYPE;
  4     R_SAL EMP.SAL%TYPE;
  5  CURSOR RES IS
  6     SELECT ENAME, SAL FROM EMP;
  7  BEGIN
  8     OPEN RES;
  9     LOOP
 10             FETCH RES INTO R_ENAME, R_SAL;
 11             EXIT WHEN RES%NOTFOUND OR RES%ROWCOUNT >3;
 12             DBMS_OUTPUT.PUT_LINE(R_ENAME||'   '||R_SAL||'   '||RES%ROWCOUNT);
 13             END LOOP;
 14     CLOSE RES;
 15  END EX_VIEW;
 16  /


8. EX_VIEW01을 호출하게 되면 사원의 이름, 봉급, 커미션이 측정된 사원만 출력하자. 

SQL> CREATE OR REPLACE PROCEDURE EX_VIEW01

  2  IS

  3     R_ENAME EMP.ENAME%TYPE;

  4     R_SAL EMP.SAL%TYPE;

  5     R_COMM EMP.COMM%TYPE;

  6  CURSOR RES IS

  7     SELECT ENAME, SAL, COMM FROM EMP

  8     WHERE COMM IS NOT NULL;

  9  BEGIN

 10  OPEN RES;

 11  LOOP

 12     FETCH RES INTO R_ENAME, R_SAL, R_COMM;

 13     EXIT WHEN RES%NOTFOUND;

 14     DBMS_OUTPUT.PUT_LINE(R_ENAME||'   '||R_SAL||'   '||R_COMM||'   ');

 15     END LOOP;

 16  CLOSE RES;

 17  END EX_VIEW01;

 18  /


9. 사원테이블에서 부서번호 20번의 사번, 이름 봉급을 출력하자.

SQL> CREATE OR REPLACE PROCEDURE EMP_EX02

  2  IS

  3     V_EMP EMP%ROWTYPE;

  4     CURSOR EMP_CURSOR IS

  5     SELECT EMPNO, ENAME, SAL

  6     FROM EMP

  7     WHERE DEPTNO = 20;

  8  BEGIN

  9     FOR V_EMP IN EMP_CURSOR LOOP

 10     EXIT WHEN EMP_CURSOR%ROWCOUNT >5 OR EMP_CURSOR%NOTFOUND;

 11     DBMS_OUTPUT.PUT_LINE(V_EMP.EMPNO||'  '||V_EMP.ENAME||'   '||V_EMP.SAL);

 12     END LOOP;

 13  END EMP_EX02;

 14  /


10. 실행 시 부서번호를 전달 커서를 통해 값을 전달해서 해당 부서번호를 출력하는 프로시저를 만들자.


SQL> CREATE OR REPLACE PROCEDURE EMP_EX03

  2  IS

  3  V_EMPNO EMP.EMPNO%TYPE;

  4     V_ENAME EMP.ENAME%TYPE;

  5     V_SAL NUMBER(7, 2);

  6     CURSOR EMP_CURSOR(V_DEPTNO NUMBER) IS -- 커서에 매개변수 선언

  7     SELECT EMPNO, ENAME, SAL

  8     FROM EMP WHERE DEPTNO = V_DEPTNO;

  9  BEGIN

 10     OPEN EMP_CURSOR(10);

 11  LOOP

 12     FETCH EMP_CURSOR INTO V_EMPNO, V_ENAME, V_SAL;

 13     EXIT WHEN EMP_CURSOR%ROWCOUNT > 5 OR EMP_CURSOR%NOTFOUND;

 14     DBMS_OUTPUT.PUT_LINE(V_EMPNO||'   '||V_ENAME||'   '||V_SAL);

 15     END LOOP;

 16     CLOSE EMP_CURSOR;

 17

 18     OPEN EMP_CURSOR(20);

 19  LOOP

 20     FETCH EMP_CURSOR INTO V_EMPNO, V_ENAME, V_SAL;

 21     EXIT WHEN EMP_CURSOR%ROWCOUNT > 5 OR EMP_CURSOR%NOTFOUND;

 22     DBMS_OUTPUT.PUT_LINE(V_EMPNO||'   '||V_ENAME||'   '||V_SAL);

 23     END LOOP;

 24     CLOSE EMP_CURSOR;

 25  END EMP_EX03;

 26  /


11. 

SQL> CREATE OR REPLACE PROCEDURE EMP_EX04(P_EMPNO IN EMP.EMPNO%TYPE)

  2  IS

  3  V_SAL EMP.SAL%TYPE;

  4  V_UPDATE_ROW NUMBER;

  5  BEGIN

  6  SELECT SAL INTO V_SAL FROM EMP

  7  WHERE EMPNO = P_EMPNO;

  8

  9  IF SQL%FOUND THEN    -- 명시적커서(SQL%)를 찾았을 때 아래를 수행하라.

 10  DBMS_OUTPUT.PUT_LINE('검색한 데이터가 존재합니다.:'||V_SAL);

 11

 12  UPDATE EMP SET SAL = SAL * 1.1

 13  WHERE DEPTNO = P_EMPNO;

 14  V_UPDATE_ROW := SQL%ROWCOUNT;

 15  DBMS_OUTPUT.PUT_LINE('급여가 인상된 사원 수 :'||V_UPDATE_ROW);

 16  END IF;

 17  END;

 18  /



12.

명시적 커서 : BEGIN안에서 지역변수처럼 사용 


13.

Example 6-22 Passing Parameters to a Cursor FOR Loop

DECLARE
  CURSOR c1 (job VARCHAR2, max_wage NUMBER) IS
    SELECT * FROM employees WHERE job_id = job AND salary > max_wage;
BEGIN
  FOR person IN c1('CLERK', 3000)
  LOOP
     -- process data record
    DBMS_OUTPUT.PUT_LINE('Name = ' || person.last_name || ', salary = ' ||
                         person.salary || ', Job Id = ' || person.job_id );
  END LOOP;
END;
/

Example 6-24 Cursor Variable Returning a %ROWTYPE Variable

DECLARE
   TYPE TmpCurTyp IS REF CURSOR RETURN employees%ROWTYPE;
   tmp_cv TmpCurTyp;  -- declare cursor variable
   TYPE EmpCurTyp IS REF CURSOR RETURN tmp_cv%ROWTYPE;
   emp_cv EmpCurTyp;  -- declare cursor variable


#4

함수


1. 정의 및 활용

- 보통 값을 계산하고 결과값을 반환하기 위해서 함수를 많이 사용

- 대부분 구성이 프로시져와 유사하지만 in 파라미터만 사용

- 반드시 반환될 값의 데이터타입을 return문에 선언하고 return문을 통해서 반드시 값을 반환


2. 형식

CREATE FUNCTION 함수명[파라미터] 

RETURN DATATYPE

IS

[변수 선언 부분]

BEGIN

-- PL/SQL 블록에는 적어도 한개의 RETURN 문이 있어야 한다.

-- PL/SQL 블록은 함수가 수행할 내용을 정의한 몸체부분이다.

END;


3. 예제 

ⓐ 사번을 입력받아 연봉을 리턴하는 함수

CREATE FUNCTION getAvg(v_id in emp.empno%type)

return number

is

v_sal emp.sal%type := 0;

vtot number := 0;

vcomm emp.comm%type;

begin

select sal, comm into v_sal, vcomm

from emp where empno = v_id ; -- 받은 사번을 입력한다.

vtot := v_sal * 12 + nvl(vcomm, 0); -- 정의된 변수를 사용한다. 연ㅅ나

return vtot;  --리턴을 명시한다.

end;

/


[실행]

var salary number; -- 반환값을 저장할 변수

exec :salary := getAvg(7900) -- 값전달 실행 확인

print -- 출력 확인


[조회]

select empno, getAvg(empno)

from emp;


ⓑ 사번을 입력받아서 부서명을 되돌리는 함수를 작성하자.

SQL> create FUNCTION getDept(p_empno in emp.empno%type)

  2  return varchar2 -- 문자열로 리턴하겠다

  3  is

  4  v_deptno emp.deptno%type; --select문에서 리턴을 하는 부서번호 대입

  5  v_res varchar2(60); --출력구문, 부서명을 저장하는 함수

  6

  7  begin

  8  select deptno into v_deptno from emp

  9  where empno = p_empno; -- 사원번호에 해당하는 부서번호 출력

 10

 11  if v_deptno = 10 then

 12     v_res := 'ACCOUNTING 부서 사원입니다';

 13  elsif v_deptno = 20 then

 14     v_res := 'Research 부서 사원입니다.';

 15  elsif v_deptno = 30 then

 16     v_res := 'SALES 부서 사원입니다';

 17  elsif v_deptno = 40 then

 18     v_res := 'OPERATIONS 부서 사원입니다.';

 19  END IF;

 20  RETURN V_RES;

 21  END;

 22 /


ⓒ 

CREATE OR REPLACE PROCEDURE ex_getDept(p_empno in emp.empno%type, v_res out varchar2)

is

V_deptno emp.deptno%type ; -- SELECT문에서 리턴을 하는 부서번호 대입

BEGIN

SELECT DEPTNO INTO V_DEPTNO FROM EMP

WHERE EMPNO = P_EMPNO; -- 사원번호에 해당하는 부서번호 출력


IF V_DEPTNO = 10 THEN

V_RES := 'ACCOUNTING 부서 사원입니다';

ELSIF V_DEPTNO = 20 THEN

V_RES := 'RESEARCH 부서 사원입니다';

ELSIF V_DEPTNO = 30 THEN

V_RES := 'SALES 부서 사원입니다.';

ELSIF V_DEPTNO = 40 THEN

V_RES := 'OPERATIONS 부서 사원입니다.';

END IF;

END;

/


[실행]

SQL> var res varchar2(50)

SQL> execute ex_getDept(7900, :res);


SQL> print


4. apex로 프로시저 만들기


#5

연습


--QUESTION(1~5 프로시져, 6~10 함수)

--1. 사원테이블에서 모든 데이터를 출력하라

SQL> CREATE OR REPLACE PROCEDURE PRO_VIEW01

  2  IS

  3  R_EMPNO EMP.EMPNO%TYPE;

  4  R_ENAME EMP.ENAME%TYPE;

  5    R_JOB EMP.JOB%TYPE;

  6    R_MGR EMP.MGR%TYPE;

  7  R_HIREDATE EMP.HIREDATE%TYPE;

  8     R_SAL EMP.SAL%TYPE;

  9   R_COMM EMP.COMM%TYPE;

 10   R_DEPTNO EMP.DEPTNO%TYPE;

 11  CURSOR RES IS

 12     SELECT * FROM EMP;

 13  BEGIN

 14     OPEN RES;

 15   LOOP

 16

 17     FETCH RES INTO R_EMPNO, R_ENAME, R_JOB, R_MGR, R_HIREDATE, R_SAL, R_COMM, R_DEPTNO;

 18     EXIT WHEN RES%NOTFOUND;

 19     DBMS_OUTPUT.PUT_LINE(R_EMPNO||'  '||R_ENAME||'   '||R_JOB||'  '||R_MGR||'   '||R_HIREDATE||'  '||R_SAL||'  '||R_COMM||'  '||R_DEPTNO);

 20  END LOOP;

 21  CLOSE RES;

 22  END PRO_VIEW01;

 23  /



--2. 사원테이블에서 사원번호, 사원이름, 월급을 출력하라

SQL> CREATE OR REPLACE PROCEDURE PRO_VIEW02

  2  IS

  3  R_EMPNO EMP.EMPNO%TYPE;

  4   R_ENAME EMP.ENAME%TYPE;

  5    R_SAL EMP.SAL%TYPE;

  6  CURSOR RES IS

  7  SELECT EMPNO, ENAME, SAL FROM EMP;

  8  BEGIN

  9     OPEN RES;

 10  LOOP

 11     FETCH RES INTO R_EMPNO, R_ENAME, R_SAL;

 12     EXIT WHEN RES%NOTFOUND;

 13     DBMS_OUTPUT.PUT_LINE(R_EMPNO||'  '||R_ENAME||'  '||R_SAL);

 14     END LOOP;

 15     CLOSE RES;

 16  END PRO_VIEW02;

 17  /



--3. 사원테이블에서 월급을 뽑는데 중복된 데이터가 없게 출력하라

SQL>  CREATE OR REPLACE PROCEDURE PRO_VIEW03

  2  IS

  3  R_SAL EMP.SAL%TYPE;

  4  CURSOR RES IS

  5  SELECT DISTINCT SAL FROM EMP;

  6  BEGIN

  7  OPEN RES;

  8   LOOP

  9  FETCH RES INTO R_SAL;

 10   EXIT WHEN RES%NOTFOUND;

 11  DBMS_OUTPUT.PUT_LINE(R_SAL);

 12   END LOOP;

 13   CLOSE RES;

 14  END PRO_VIEW03;

 15  /


--4. 사원테이블에서 사원이름과 월급을 출력하는데 각각의 컬럼명을

-- '이 름','월 급'으로 바꿔서 출력하라. 단, ALIAS에 공백추가


SQL> CREATE OR REPLACE PROCEDURE PRO_VIEW04

  2  IS

  3  R_ENAME EMP.ENAME%TYPE;

  4  R_SAL EMP.SAL%TYPE;

  5  CURSOR RES IS

  6  SELECT ENAME, SAL FROM EMP;

  7  BEGIN

  8  OPEN RES;

  9  DBMS_OUTPUT.PUT_LINE('이   름'||'   '||'월   급');

 10  LOOP

 11  FETCH RES INTO R_ENAME, R_SAL;

 12  EXIT WHEN RES%NOTFOUND;

 13  DBMS_OUTPUT.PUT_LINE(R_ENAME||'   '||R_SAL);

 14   END LOOP;

 15  CLOSE RES;

 16  END PRO_VIEW04;

 17  /


--5. 사원테이블에서 사원이름, 월급을 뽑고, 월급과 커미션을  더한 값을

-- 출력하는데 컬럼명을 '실급여'이라고 해서 출력하라.

-- 단, NULL값은 나타나지 않게 하라.


SELECT ENAME, SAL, (ENAME + NVL(COMM,0)) "실급여" FROM EMP;




--6. 사원테이블에서 'SCOTT'이라는 사원의 사원번호, 이름, 월급을 출력하라

CREATE FUNCTION EX06( MYNAME  IN  EMP.ENAME%TYPE )

  RETURN SYS_REFCURSOR

IS       

     RES   SYS_REFCURSOR;            

BEGIN

    OPEN RES FOR

   SELECT EMPNO, ENAME, SAL 

   FROM EMP

   WHERE  ENAME =MYNAME;

    RETURN RES;

END;     


 SQL> VAR MY REFCURSOR

 SQL> EXEC :MY := EX06('SCOTT');






SQL> CREATE OR REPLACE FUNCTION PRO_VIEW06(

  2     V_ENAME IN EMP.ENAME%TYPE,

  3     V_EMPNO OUT EMP.EMPNO%TYPE,

  4     V_ENAME OUT EMP.ENAME%TYPE,

  5     V_SAL OUT EMP.SAL%TYPE)

  6  RETURN NUMBER

  7  IS

  8     V_EMPNO EMP.EMPNO%TYPE;

  9     V_ENAME EMP.ENAME%TYPE;

 10     V_SAL   EMP.SAL%TYPE;

 11  BEGIN

 12     SELECT EMPNO, SAL

 13             INTO V_EMPNO, V_SAL

 14             FROM EMP

 15             WHERE ENAME = V_ENAME;

 16     SELECT ENAME

 17             INTO V_ENAME

 18             FROM EMP

 19             WHERE ENAME = V_ENAME;

 20     DBMS_OUTPUT.PUT_LINE('성  명: ' ||V_ENAME);

 21     DBMS_OUTPUT.PUT_LINE('사  번: ' ||TO_CHAR(V_EMPNO));

 22     DBMS_OUTPUT.PUT_LINE('급  여: ' ||TO_CHAR(V_SAL));

 23     RETURN EMPNO;

 24  END;

 25  /



문제5) EMP 테이블에서 이름을 입력 받아 부서번호,부서명,급여를 검색하는 FUNCTION을 작성하여라단 부서번호를 RETURN에 사용하여라.

CREATE OR REPLACE FUNCTION emp_disp(

        v_ename IN      emp.ename%TYPE,

        v_dname OUT     dept.dname%TYPE,

        v_sal   OUT     emp.sal%TYPE)

RETURN NUMBER

IS

        v_deptno       emp.deptno%TYPE;

        v_dname_temp   dept.dname%TYPE;

        v_sal_temp     emp.sal%TYPE;

BEGIN

        SELECT sal,deptno

               INTO v_sal_temp,v_deptno

               FROM emp

               WHERE ename = UPPER(v_ename);

        SELECT dname

               INTO v_dname_temp

               FROM dept

               WHERE deptno = v_deptno;

        v_dname := v_dname_temp;

        v_sal := v_sal_temp;

        DBMS_OUTPUT.PUT_LINE('     : ' || v_ename);

        DBMS_OUTPUT.PUT_LINE('부서번호 : ' || TO_CHAR(v_deptno));

        DBMS_OUTPUT.PUT_LINE('부 서 명 : ' || v_dname_temp);

        DBMS_OUTPUT.PUT_LINE('     : ' || TO_CHAR(v_sal_temp,'$999,999'));

        RETURN v_deptno;

EXCEPTION

        WHEN NO_DATA_FOUND THEN

               DBMS_OUTPUT.PUT_LINE('입력한 MANAGER는 없습니다.');

        WHEN TOO_MANY_ROWS THEN

               DBMS_OUTPUT.PUT_LINE('자료가 2건 이상입니다.');

        WHEN OTHERS THEN

               DBMS_OUTPUT.PUT_LINE('기타 에러입니다.');

END;

/



출처: https://laserbit.tistory.com/entry/오라클-FUNCTION-생성 [미친듯이파고든다]


/

DECLARE

V_EMP EMP%ROWTYPE;

BEGIN

V_EMP := EX06('KING');

DBMS_OUTPUT.PUT_LINE(V_EMP.EMPNO || '    ' || V_EMP.ENAME || '    ' || V_EMP.SAL);

END;

/

--7. 사원테이블에서 직위가 'SALESMAN'인 사원의 사원번호, 이름, 직위를

-- 출력하라

SELECT EMPNO, ENAME, JOB FROM EMP WHERE JOB = 'SALESMAN';



  CREATE FUNCTION EX06( MYJOB  IN  EMP.JOB%TYPE )

  RETURN SYS_REFCURSOR

IS       

     RES   SYS_REFCURSOR;            

BEGIN

    OPEN RES FOR

   SELECT EMPNO, ENAME, JOB

   FROM EMP

   WHERE  JOB =MYJOB;

    RETURN RES;

END;     


--8. 사원테이블에서 사원번호가 7499, 7521, 7654인 사원의 사원번호, 이름

-- 월급을 출력하라

SELECT EMPNO, ENAME, SAL FROM EMP WHERE EMPNO IN (7499, 7521, 7654) 


--9. 사원테이블에서 월급이 1500에서 3000사이인 사원의 사원번호, 이름,

-- 월급을 출력하라.


SELECT EMPNO, ENAME, SAL FROM EMP WHERE SAL BETWEEN 1500 AND 3000;


--10. 사원테이블에서 이름의 첫글자가 A이고 마지막 글자가 N이 아닌 사원의

-- 이름을 출력하라


SELECT ENAME FROM EMP WHERE SELECT SUBSTR(ENAME, 1) FROM EMP = 'A' AND SELECT SUBSTR(ENAME, -1) FROM EMP != 'N' 

'국비교육' 카테고리의 다른 글

1월 30일 국비교육  (0) 2019.01.30
1월 29일 국비교육  (0) 2019.01.29
1월 25일 국비교육  (0) 2019.01.25
1월 24일 국비교육  (0) 2019.01.24
1월 23일 국비교육  (0) 2019.01.23

댓글