ㅁ PL/SQL은 데이터베이스 객체같은 것은 아니고 문법이다.
ㅁ < PL/SQL >
- Procedure Language extension to SQL
- 오라클 내에 내장되어 있는 절차적 언어
- 변수의 정의, 조건/반복처리
ㅁ PL/SQL 구조
- 선언부 : DELCARE로 시작. 변수 및 상수를 선언 및 초기화 가능.
- 실행부 : BEGIN으로 시작. 실행부는 필수로 작성해야 한다. SQL문 또는 제어문(조건/반복) 로직 기술 가능.
- 예외처리부 : EXCEPTION으로 시작. 예외발생시 실행할 구문을 미리 정의.
ㅁ 화면에 문구 출력
ㅇ 출력결과를 보기 위해서 SERVEROUTPUT 옵션을 ON으로 설정해야 한다. (기본값은 OFF이다)
SET SERVEROUTPUT ON;
ㅇ BEGIN~END; 는 필수다. 그리고 "/"까지 넣어줘야 한다. (EXCEPTION은 END 전에 넣는다)
BEGIN
DBMS_OUTPUT.PUT_LINE('HELLO ORACLE');
END;
/
- PL/SQL 문 입력이 끝났음을 SQL *Plus 에 알리기 위해, 마지막에 슬래시(/) 를 입력해야 한다.
- 슬래시 자체가 한 행에 나와야 한다
- PL/SQL의 실행부(혹은 예외처리부)까지 모두 작성한 후에는 슬래시를 이용해 프로그램 작성이 끝났음을 알리고 실행한다.
- PL/SQL문 작성을 마치고 실행하기 위해 마지막에 슬래시(/)를 사용.
ㅁ DECLARE 선언부
- 변수 및 상수를 선언, 초기화하는 공간
- 일반타입 변수, 레퍼런스타입 변수, ROW타입 변수 3가지를 만들 수 있다.
(1) 일반타입 변수 선언 및 초기화
변수명 [CONSTANT] 데이터타입 [ := 값 ];
- CONSTANT를 붙여서 상수로 선언할 수 있다.
- 선언부에서 선언된 변수는 실행부에서 사용 가능.
- 쌍따옴표 쓰면 안 됨. 오라클은.
- 자바는 '+'로 문자열을 연결하지만, 오라클은 연결연산자( || )를 사용한다.
ㅇ & 사용
- SQLPlus에서 & 기호로 시작하는 변수는 사용자에게 값을 입력받는 매개변수(parameter)로 사용될 수 있습니다.
- EID와 ENAME에 데이터를 입력하면 그 값이 출력된다.
(2) 레퍼런스 타입 변수 선언 및 초기화
- 특정 테이블의 특정 컬럼의 데이터타입을 참조해서 동일하게 지정한다.
변수명 테이블명.컬럼명%TYPE;
- %TYPE은 이 컬럼의 데이터타입과 맞춰주겠다는 뜻.
- 선언한 테이블의 컬럼타입과 같은 타입으로 설정
- EMP_ID는 문자 타입이다. 물론 그냥 숫자를 써도 자동 형변환되긴 하지만 타입을 맞춰주는 것이 좋다.
- 사용자에게 입력창이 뜨고, 거기에 200을 입력하면 저렇게 나온다.
ㅇ예제
레퍼런스타입 변수로 EID, ENAME, JCODE, SAL, DTITLE을 선언하고
각 자료형을 EMPLOYEE(EMP_ID, EMP_NAME, JOB_CODE, SALARY), DEPARTMENT(DEPT_TITLE)로 참조.
사용자가 입력한 사번의 사원 조회
사번, 사원명, 직급코드, 급여, 부서명을 조회한 후 각 변수에 담아 출력.
- SELECT INTO로 넣을 때는 데이터가 없어도 안되고, 여러 행이어도 안 됨. 한 행이어야 한다.
- DBMS_OUTPUT.PUT_LINE( ) 안에 컴마로 여러 변수 출력 불가능.
DBMS_OUTPUT.PUT_LINE 함수는 인자로 하나의 문자열만을 받을 수 있습니다.
여러 개의 변수를 출력하려면 각 변수를 문자열로 변환하여 연결해야 합니다.
DBMS_OUTPUT.PUT_LINE(EID || ENAME || SAL || JCODE || DTITLE);
(3) ROW 타입 변수 선언
- 테이블의 한 행에 대한 모든 컬럼값을 한번에 담을 수 있는 변수
변수명 테이블명%ROWTYPE;
- E 라는 변수에 13개의 컬럼값이 통째로 담긴다.
- E라는 변수 통째로 출력 가능하냐 .불가능. 오류남.
E에 담겨있는 값중 어떤 컬럼의 값을 가져올 걸지 지정해줘야 한다.
- 보너스가 NULL이라 안 나옴.
- DBMS_OUTPUT.PUT_LINE('보너스: ' || NVL(E.BONUS, 0));
이러면 NULL이면 0으로 나옴.
====================================================================================
ㅁ BEGIN 실행부
- 실행할 SQL문, 제어문(조건문/반복문) 등의 로직 기술 가능.
(1) 조건문
IF 조건식1
THEN 실행내용1
ELSIF 조건식2
THEN 실행내용2
ELSE 실행내용N
END IF;
- ELSIF 부분과 ELSE 부분은 생략 가능.
ㅇ 사번을 입력받은 후 해당 사원의 사번, 이름, 급여, 보너스율(%)을 출력하기.
단, 보너스를 받지 않는 사원은 보너스를 출력전 '보너스를 지급받지 않는 사원입니다' 출력
- 만약 SELECT절에서 NVL(BONUS, 0)으로 작성했다면, IF 조건식을 IF BONUS = 0으로 해야 함.
ㅇ 예제
레퍼런스타입 변수(EID, ENAME, DTITLE, NCODE) 선언
일반타입 변수(TEAM 문자타입) 선언 <- '국내팀' 또는 '해외팀' 대입 예정
NCODE는 NATIONAL코드. LOCATION 테이블, NATIONAL 테이블에 있다.
사용자가 입력한 사번의 사원을 조회
사번, 이름, 부서명, 근무국가코드 조회 후 레퍼런스타입 변수에 대입
이때 NCODE값이 'KO'일 경우 TEAM변수에 '국내팀' 대입, 그게 아니면 '해외팀' 대입.
결과 출력 (사번, 이름, 부서명, 소속)
DECLARE
EID EMPLOYEE.EMP_ID%TYPE;
ENAME EMPLOYEE.EMP_NAME%TYPE;
DTITLE DEPARTMENT.DEPT_TITLE%TYPE;
NCODE LOCATION.NATIONAL_CODE%TYPE;
TEAM VARCHAR2(9);
BEGIN
SELECT EMP_ID, EMP_NAME, DEPT_TITLE, NATIONAL_CODE
INTO EID, ENAME, DTITLE, NCODE
FROM EMPLOYEE
JOIN DEPARTMENT ON DEPT_CODE = DEPT_ID
JOIN LOCATION ON LOCATION_ID = LOCAL_CODE
WHERE EMP_ID = '&사번'
;
IF NCODE = 'KO'
THEN TEAM := '국내팀';
ELSE
TEAM := '해외팀';
END IF;
DBMS_OUTPUT.PUT_LINE(EID);
DBMS_OUTPUT.PUT_LINE(ENAME);
DBMS_OUTPUT.PUT_LINE(DTITLE);
DBMS_OUTPUT.PUT_LINE(NCODE);
END;
/
- THEN 써야 함. 또 그곳에 세미콜론 써야 함.
- PL/SQL에서 변수에 대입할 때는 := 써야 함.
ㅇ 예제
사용자에게 입력받은 사번의 사원의 급여를 조회해서 SAL 변수에 대입.
급여가 500만 이상이면 '고급'
급여가 300만 이상이면 '중급'
급여가 300만 미만이면 '초급'
'해당 사원의 급여등급은 XX입니다'
DECLARE
SAL EMPLOYEE.SALARY%TYPE;
GRADE VARCHAR2(10);
BEGIN
SELECT SALARY
INTO SAL
FROM EMPLOYEE
WHERE EMP_ID = '&사번';
IF SAL >= 5000000
THEN GRADE := '고급';
ELSIF SAL >= 3000000
THEN GRADE := '중급';
ELSE
GRADE := '초급';
END IF;
DBMS_OUTPUT.PUT_LINE('해당 사원의 급여 등급은 ' || GRADE || '입니다');
END;
/
(2) 조건문 (CASE WHEN THEN END)
CASE 비교대상자
WHEN 비교값1 THEN 결과값1
WHEN 비교값2 THEN 결과값2
....
ELSE 결과값N
END;
ㅇ 예시
DECLARE
EMP EMPLOYEE%ROWTYPE;
GEN CHAR(6);
BEGIN
SELECT *
INTO EMP
FROM EMPLOYEE
WHERE EMP_ID = '&사번';
GEN := CASE SUBSTR(EMP.EMP_NO, 8, 1)
WHEN '1' THEN '남자'
WHEN '2' THEN '여자'
WHEN '3' THEN '남자'
WHEN '4' THEN '여자'
END;
DBMS_OUTPUT.PUT_LINE(GEN || '입니다');
END;
/
(3) 반복문(BASIC LOOP문)
LOOP
반복적으로 실행할 구문;
= 반복문을 빠져나갈 수 있는 구문(어떤 경우에 반복 종료할건지)
END LOOP;
- 기본적으로 BASIC LOOP문은 무한반복이다.
- 반복문을 빠져나가는 구문 2가지.
i) IF 조건식
THEN EXIT;
END IF;
ii) EXIT WHEN 조건식;
ㅇ 예시
DECLARE
I NUMBER := 1;
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE(I);
I := I+1;
IF I=6
THEN EXIT;
END IF;
END LOOP;
END;
/
(4) 반복문 (FOR LOOP문)
FOR 변수 IN [REVERSE] 초기값 .. 최종값
LOOP
반복적으로 실행할 구문;
END LOOP;
- 변수가 초기값부터 최종값까지 1씩 증가함.
- IN REVERSE로 하면 최종값부터 초기값까지 1씩 감소함.
ㅇ 예시
BEGIN
FOR I IN 1..5
LOOP
DBMS_OUTPUT.PUT_LINE(I);
END LOOP;
END;
/
- 얘는 DECLARE도 필요없다. 변수를 선언할 필요도 없음.
- .이 두 개다.
ㅇ 예시
DROP TABLE TEST;
CREATE TABLE TEST (
TNO NUMBER PRIMARY KEY,
TDATE DATE
);
CREATE SEQUENCE SEQ_TNO
MAXVALUE 1000
NOCYCLE
NOCACHE;
- TNO에 절대 겹치지 않는 숫자가 들어가게 할 것.
BEGIN
FOR I IN 1..100
LOOP
INSERT INTO TEST VALUES(SEQ_TNO.NEXTVAL, SYSDATE-I);
END LOOP;
END;
/
SELECT *
FROM TEST;
- 샘플 데이터 넣을 때 이렇게 반복문 활용 가능하다.
- FOR LOOP문을 한번 더 실행하고 조회하면 시퀀스라 그 다음 값(101)이 나옴.
(5) 반복문 (WHILE LOOP)
WHILE 반복문이수행될조건
LOOP
반복적으로 실행할 구문;
END LOOP;
- 반복문이수행될조건이 FALSE가 되면 반복이 종료됨.
ㅇ 예시
DECLARE
I NUMBER := 1;
BEGIN
WHILE I<6
LOOP
DBMS_OUTPUT.PUT_LINE(I);
I := I+1;
END LOOP;
END;
/
===============================================================================
ㅁ 예외처리부
EXCEPTION
WHEN 예외명1 THEN 예외처리구문1;
WHEN 예외명2 THEN 예외처리구문2;
...
WHEN OTHERS THEN 예외처리구문N;
※ 시스템예외 (오라클에서 미리 정의해둔 예외. 엄청 많음)
- NO_DATA_FOUND : SELECT한 결과가 한 행도 없을 경우
- TOO_MANY_ROWS : SELECT한 결과가 여러 행일 경우
- ZERO_DIVIDE : 0으로 나눌 때
- DUP_VAL_ON_INDEX : UNIQUE 제약조건에 위배되었을 경우
ㅇ ZERO_DIVIDE 예시
- 예외처리부를 넣지 않았을 때.
- 예외명을 모르겠다면 OTHERS를 써도 됨.
OTHERS로 써놓고 0을 입력해도 똑같이 나옴.
ㅇ UNIQUE 제약조건 위배 예시 ( DUP_VAL_ON_INDEX )
BEGIN
UPDATE EMPLOYEE
SET EMP_ID = '&변경할사번'
WHERE EMP_NAME = '노옹철';
END;
/
- 999 입력하면 잘 됨. 999 사번은 존재하지 않음.
200 입력하면 "unique constraint (%s.%s) violated" 뜸. 200은 이미 존재함.
- 이미 존재하는 사번 입력시 '이미 존재하는 사번입니다.'가 출력됨.
ㅇ NO_DATA_FOUND, TOO_MANY_FOWS 예시
DECLARE
EID EMPLOYEE.EMP_ID%TYPE;
ENAME EMPLOYEE.EMP_NAME%TYPE;
BEGIN
SELECT EMP_ID, EMP_NAME
INTO EID, ENAME
FROM EMPLOYEE
WHERE MANAGER_ID = '&사수사번';
DBMS_OUTPUT.PUT_LINE(EID);
DBMS_OUTPUT.PUT_LINE(ENAME);
EXCEPTION
WHEN TOO_MANY_ROWS THEN DBMS_OUTPUT.PUT_LINE('너무 많은 행이 조회되었습니다.');
WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('조회 결과가 없습니다.');
END;
/
- 발생될만한 예외는 두 가지. 데이터가 없거나 두 개이상이거나. 무조건 한 개여야 함.
- "no data found", "exact fetch returns more than requested number of rows(여러 행인 경우)"
'클라우드 활용 자바개발자 양성과정 > 02. 데이터베이스 활용' 카테고리의 다른 글
13. OBJECT(TRIGGER) (0) | 2024.07.25 |
---|---|
11.OBJECT(VIEW) (2) | 2024.07.24 |
10. OBJECT(SEQUENCE) (6) | 2024.07.24 |
09. TCL(COMMIT, ROLLBACK + SAVEPOINT) (2) | 2024.07.24 |
08_DDL(ALTER, DROP) + DCL(GRANT, REVOKE) (0) | 2024.07.23 |