Oracle DB/orcle sql
[ Oracle sql ] 11. PL/SQL
HAyooni
2022. 8. 6. 18:38
1. PL/SQL (Procedural Language Extension to SQL)
오라클 자체에 내장되어있는 절차적 언어, 변수의 정의, 조건처리, 반복처리 등을 지원하여 SQL 단점 보완
2. PL/SQL의 구조

DECLARE
EMP_ID NUMBER;
EMP_NAME VARCHAR2(30);
PI CONSTANT NUMBER := 3.14; --오라클에서 상수는 CONSTANT 로 지정
BEGIN
EMP_ID := 888;
EMP_NAME := '도대담';
DBMS_OUTPUT.PUT_LINE('EMP_ID : ' || EMP_ID);
DBMS_OUTPUT.PUT_LINE('EMP_NAME : ' || EMP_NAME);
DBMS_OUTPUT.PUT_LINE('PI : ' || PI);
END;
/
DECLARE
EMP_ID EMPLOYEE.EMP_ID%TYPE;
EMP_NAME EMPLOYEE.EMP_NAME%TYPE;
BEGIN
SELECT EMP_ID, EMP_NAME
INTO EMP_ID, EMP_NAME
--조회해온 결과를 위 선언한 변수에다가 집어넣기
FROM EMPLOYEE
WHERE EMP_ID = '&EMP_ID';
-- '' 리터럴안에 & 을 사용하여 사용자에게 값을 입력받을 수 있다
DBMS_OUTPUT.PUT_LINE('EMP_ID : ' || EMP_ID);
DBMS_OUTPUT.PUT_LINE('EMP_NAME : ' || EMP_NAME);
END;
/
----------전체정보 저장하기 ROWTYPE----------------
DECLARE
E EMPLOYEE%ROWTYPE;
BEGIN
SELECT * INTO E
FROM EMPLOYEE
WHERE EMP_ID = '&사번';
DBMS_OUTPUT.PUT_LINE('EMP_ID : ' || E.EMP_ID);
DBMS_OUTPUT.PUT_LINE('EMP_NAME : ' || E.EMP_NAME);
DBMS_OUTPUT.PUT_LINE('SALARY : ' || E.SALARY);
END;
/
* CONSTANT : 상수 지정
*리터럴 안에 & 을 사용하여 사용자에게 값을 입력받기
*ROWTYPE을 통하여 전체 정보를 변수로 선언하여 저장할 수 있다.
예 ) PL/SQL의 구조

3. IF~THEN~END IF (단일 IF문)의 예시
예 ) EMP_ID를 입력받아 해당 사원의 사번, 이름, 급여, 보너스 출력 이 때, 보너스를 받지 않는 사원은 보너스율 출력 전 '보너스를 지급받지 않는 사원입니다.' 출력
DECLARE
EMP_ID EMPLOYEE.EMP_ID%TYPE;
EMP_NAME EMPLOYEE.EMP_NAME%TYPE;
SALARY EMPLOYEE.SALARY%TYPE;
BONUS EMPLOYEE.BONUS%TYPE;
BEGIN
SELECT EMP_ID, EMP_NAME, SALARY, NVL(BONUS,0)
INTO EMP_ID, EMP_NAME, SALARY, BONUS
FROM EMPLOYEE
WHERE EMP_ID = '&EMP_ID';
DBMS_OUTPUT.PUT_LINE('EMP_ID : ' || EMP_ID);
DBMS_OUTPUT.PUT_LINE('EMP_NAME : ' || EMP_NAME);
DBMS_OUTPUT.PUT_LINE('SALARY : ' ||SALARY);
IF(BONUS = 0)
THEN DBMS_OUTPUT.PUT_LINE('보너스를 지급받지 않는 사원입니다.');
END IF;
DBMS_OUTPUT.PUT_LINE('BONUS : ' || BONUS*100 || '%');
END;
/
4. IF~THEN~ELSE~END IF (IF~ELSE문)의 예시
예) EMP_ID를 입력받아 해당 사원의 사번, 이름, 부서명, 소속 출력하고 TEAM 변수를 만들어 소속이 KO인 사원은 국내팀, 아닌 사원은 해외팀으로 저장
DECLARE
EMP_ID EMPLOYEE.EMP_ID%TYPE;
EMP_NAME EMPLOYEE.EMP_NAME%TYPE;
DEPT_TITLE DEPARTMENT.DEPT_TITLE%TYPE;
NATIONAL_CODE LOCATION.NATIONAL_CODE%TYPE;
TEAM VARCHAR2(10);
BEGIN
SELECT EMP_ID, EMP_NAME, DEPT_TITLE, NATIONAL_CODE
INTO EMP_ID, EMP_NAME, DEPT_TITLE, NATIONAL_CODE
FROM EMPLOYEE
LEFT JOIN DEPARTMENT ON (DEPT_ID = DEPT_CODE)
LEFT JOIN LOCATION ON (LOCAL_CODE = LOCATION_ID)
WHERE EMP_ID = '&EMP_ID';
IF(NATIONAL_CODE = 'KO')
THEN TEAM := '국내팀';
ELSE
TEAM := '해외팀';
END IF;
DBMS_OUTPUT.PUT_LINE('사원 : ' || EMP_ID);
DBMS_OUTPUT.PUT_LINE('이름 : ' || EMP_NAME);
DBMS_OUTPUT.PUT_LINE('부서 : ' || DEPT_TITLE);
DBMS_OUTPUT.PUT_LINE('소속 : ' || TEAM);
END;
/
예 ) 사용자에게 사번을 받아와 그 사원의 전체 정보를 VEMP에 저장하고 VEMP를 이용하여 연봉계산(보너스가 있는 사원은 보너스도 포함하여 계산) , 연봉 계산 결과 값은 YSLALRY에 저장, 급여 이름 연봉 (\1,000,000 형식)으로 출력
DECLARE
VEMP EMPLOYEE%ROWTYPE;
YSALARY NUMBER;
BEGIN
SELECT * INTO VEMP
FROM EMPLOYEE
WHERE EMP_ID = '&EMP_ID';
IF (VEMP.BONUS IS NOT NULL)
THEN YSALARY := VEMP.SALARY * (1 + VEMP.BONUS) * 12;
ELSE YSALARY := VEMP.SALARY * 12;
END IF;
--YSALARY := TO_CHAR((VEMP.SALARY+(VEMP.SALARY*NVL(VEMP.BONUS, 0)))*12, 'FML999,999,999');
DBMS_OUTPUT.PUT_LINE('급여 : ' || VEMP.SALARY);
DBMS_OUTPUT.PUT_LINE('이름 : ' || VEMP.EMP_NAME);
DBMS_OUTPUT.PUT_LINE('연봉 : ' || TO_CHAR(YSALARY, 'FML999,999,999'));
END;
/
5. IF~THEN~ELSIF`THEN~ELSE~END IF (IF~ELSE IF~ELSE문)의 예시
예) 점수를 입력받아 SOCRE변수에 저장
-- 90점 이상이면 A, 80점 이상이면 B, 70학점 이상은 C 학점, 60점 이상은 D학점, 그 미만은 F 처리하여 GRADE변수에 저장
-- 출력 : 당신의 점수는 N점이고, 학점은 M학점입니다.
DECLARE
SCORE NUMBER;
GRADE VARCHAR2(1);
BEGIN
SCORE := '&점수';
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;
DBMS_OUTPUT.PUT_LINE('당신의 점수는 ' || SCORE ||'점이고, 학점은 ' || GRADE || '학점입니다.');
END;
/
6. CASE~WHEN~THEN~DEN (SWITCH문)의 예시
예 ) 사원번호를 입력받아 해당 사원의 사번, 이름, 부서명 출력
DECLARE
EMP EMPLOYEE%ROWTYPE;
DNAME DEPARTMENT.DEPT_TITLE%TYPE;
BEGIN
SELECT * INTO EMP
FROM EMPLOYEE
WHERE EMP_ID = '&EMP_ID';
DNAME := CASE
WHEN EMP.DEPT_CODE = 'D1' THEN '인사관리부'
WHEN EMP.DEPT_CODE = 'D2' THEN '회계관리부'
WHEN EMP.DEPT_CODE = 'D3' THEN '마케팅부'
WHEN EMP.DEPT_CODE = 'D4' THEN '국내영업부'
WHEN EMP.DEPT_CODE = 'D5' THEN '해외영업1부'
WHEN EMP.DEPT_CODE = 'D6' THEN '해외영업2부'
WHEN EMP.DEPT_CODE = 'D7' THEN '해외영업3부'
WHEN EMP.DEPT_CODE = 'D8' THEN '기술지원부'
WHEN EMP.DEPT_cODE = 'D9' THEN '총무부'
ELSE '배정X'
END;
-- 다르게 쓰는 방법
DNAME := CASE EMP.DEPT_CODE
WHEN 'D1' THEN '인사관리부'
WHEN 'D2' THEN '회계관리부'
WHEN 'D3' THEN '마케팅부'
WHEN 'D4' THEN '국내영업부'
WHEN 'D5' THEN '해외영업1부'
WHEN 'D6' THEN '해외영업2부'
WHEN 'D7' THEN '해외영업3부'
WHEN 'D8' THEN '기술지원부'
WHEN 'D9' THEN '총무부'
ELSE '배정X'
END;
DBMS_OUTPUT.PUT_LINE(EMP.EMP_ID || ' ' || EMP.EMP_NAME || ' ' || DNAME);
END;
/
7. 반복문 이용하기
예 ) 1부터 5까지 출력
--------------------BASIC LOOP----------------------------
DECLARE
N NUMBER := 1;
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE(N);
N := N +1;
-- IF N > 5 THEN EXIT;
-- END IF;
EXIT WHEN N >5;
END LOOP;
END;
/
--------------------FOR LOOP----------------------------
BEGIN
FOR N IN 1..5 -- FOR N IN (더작은 숫자 .. 큰 숫자)
LOOP
DBMS_OUTPUT.PUT_LINE(N);
END LOOP;
END;
/
--------------------WHILE LOOP----------------------------
DECLARE
N NUMBER :=1;
BEGIN
WHILE N <= 5
LOOP
DBMS_OUTPUT.PUT_LINE(N);
N := N +1;
END LOOP;
END;
/
DECLARE
N NUMBER := 5;
BEGIN
WHILE N >=1
LOOP
DBMS_OUTPUT.PUT_LINE(N);
N := N - 1;
END LOOP;
END;
/
* REVERSE 를 이용하여 반대로 출력가능
[예제] 반복문을 이용하여 구구단 만들기
---------------------FOR문 구구단 출력 (단, 짝수단 출력)
DECLARE
RESULT NUMBER;
DAN NUMBER;
SU NUMBER;
BEGIN
FOR DAN IN 2..9 LOOP
IF (MOD(DAN, 2) = 0)
THEN
FOR SU IN 1..9 LOOP
RESULT := DAN * SU;
DBMS_OUTPUT.PUT_LINE(DAN || '*'|| SU||'='|| RESULT);
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
END IF;
END LOOP;
END;
/
---------------------WHILE문 (단, 짝수단 출력)
DECLARE
RESULT NUMBER;
DAN NUMBER :=2;
SU NUMBER;
BEGIN
WHILE DAN <=9 LOOP
SU := 1;
IF MOD(DAN, 2) =0
THEN
WHILE SU<=9 LOOP
RESULT := DAN * SU;
DBMS_OUTPUT.PUT_LINE(DAN || ' * ' || SU || ' = ' || RESULT);
SU := SU + 1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
END IF;
DAN := DAN+1;
END LOOP;
END;
/
---------------------FOR문 - WHILE문 (단, 짝수단 출력)
DECLARE
SU NUMBER;
BEGIN
FOR DAN IN 2..9 LOOP
IF MOD(DAN, 2) = 0 THEN
SU :=1;
WHILE SU<=9 LOOP
DBMS_OUTPUT.PUT_LINE(DAN || '*' || SU || '=' || DAN*SU);
SU:=SU+1;
END LOOP;
END IF;
END LOOP;
END;
/
---------------------WHILE문 - FOR문 (단, 짝수단 출력)
DECLARE
DAN NUMBER :=2;
BEGIN
WHILE DAN <=9 LOOP
IF MOD(DAN, 2) =0 THEN
FOR SU IN 1..9 LOOP
DBMS_OUTPUT.PUT_LINE(DAN || '*' || SU || '=' || DAN*SU);
END LOOP;
END IF;
DAN := DAN + 1;
END LOOP;
END;
/
8. 예외처리 NO_DATE_FOUND : SELECT문이 데이터 행을 반환
--------------------- 예외----------------------
-- NO_DATE_FOUND : SELECT문이 데이터 행을 반환
DECLARE
NAME VARCHAR(30);
BEGIN
SELECT EMP_NAME INTO NAME
FROM EMPLOYEE
WHERE EMP_ID = 0;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('조회결과가 없습니다.');
END;
/