SELECT 열1, 열2, ..., 열n INTO 변수1, 변수2, ..., 변수n
FROM ...
DECLARE
V_DEPT_ROW DEPT%ROWTYPE;
BEGIN
SELECT DEPTNO, DNAME, LOC INTO V_DEPT_ROW
FROM DEPT
WHERE DEPTNO = 40;
DBMS_OUTPUT.PUT_LINE('DEPTNO : ' || V_DEPT_ROW.DEPTNO);
DBMS_OUTPUT.PUT_LINE('DNAME : ' || V_DEPT_ROW.DNAME);
DBMS_OUTPUT.PUT_LINE('LOC : ' || V_DEPT_ROW.LOC);
END;
/
DECLARE
CURSOR 커서이름 IS SQL문; -- 커서 선언(Declaration)
BEGIN
OPEN 커서 이름; -- 커서 열기(Open)
FETCH 커서 이름 INTO 변수 -- 커서로부터 읽어온 데이터 사용(Fetch)
CLOSE 커서 이름; -- 커서 닫기(Close)
END;
DECLARE
-- 커서 데이터를 입력할 변수 선언
V_DEPT_ROW DEPT%ROWTYPE;
-- 명시적 커서 선언(Declaration)
CURSOR c1 IS
SELECT DEPTNO, DNAME, LOC
FROM DEPT
WHERE DEPTNO = 40;
BEGIN
-- 커서 열기(Open)
OPEN c1;
-- 커서로부터 읽어온 데이터 사용(Fetch)
FETCH c1 INTO V_DEPT_ROW;
DBMS_OUTPUT.PUT_LINE('DEPTNO : ' || V_DEPT_ROW.DEPTNO);
DBMS_OUTPUT.PUT_LINE('DNAME : ' || V_DEPT_ROW.DNAME);
DBMS_OUTPUT.PUT_LINE('LOC : ' || V_DEPT_ROW.LOC);
-- 커서 닫기(Close)
CLOSE c1;
END;
/
DECLARE
-- 커서 데이터를 입력할 변수 선언
V_DEPT_ROW DEPT%ROWTYPE;
-- 명시적 커서 선언(Declaration)
CURSOR c1 IS
SELECT DEPTNO, DNAME, LOC
FROM DEPT;
BEGIN
-- 커서 열기(Open)
OPEN c1;
LOOP
-- 커서로부터 읽어온 데이터 사용(Fetch)
FETCH c1 INTO V_DEPT_ROW;
-- 커서의 모든 행을 읽어오기 위해 %NOTFOUND 속성 지정
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('DEPTNO : ' || V_DEPT_ROW.DEPTNO
|| ', DNAME : ' || V_DEPT_ROW.DNAME
|| ', LOC : ' || V_DEPT_ROW.LOC);
END LOOP;
-- 커서 닫기(Close)
CLOSE c1;
END;
/
속성 | 설명 |
---|---|
커서 이름%NOTFOUND | 수행된 FETCH문을 통해 추출된 행이 있으면 false, 없으면 true를 반환한다. |
커서 이름%FOUND | 수행된 FETCH문을 통해 추출된 행이 있으면 true, 없으면 false를 반환한다. |
커서 이름%ROWCOUNT | 현재까지 추출된 행 수를 반환한다. |
커서 이름%ISOPEN | 커서가 열려(open) 있으면 true, 닫혀(close) 있으면 false를 반환한다. |
FOR 루프 인덱스 이름 IN 커서 이름 LOOP
결과 행별로 반복 수행할 작업;
END LOOP;
DECLARE
-- 명시적 커서 선언(Declaration)
CURSOR c1 IS
SELECT DEPTNO, DNAME, LOC
FROM DEPT;
BEGIN
-- 커서 FOR LOOP 시작 (자동 Open, Fetch, Close)
FOR c1_rec IN c1 LOOP
DBMS_OUTPUT.PUT_LINE('DEPTNO : ' || c1_rec.DEPTNO
|| ', DNAME : ' || c1_rec.DNAME
|| ', LOC : ' || c1_rec.LOC);
END LOOP;
END;
/
CURSOR 커서 이름(파라미터 이름 자료형, ...) IS
SELECT ...
DECLARE
-- 커서 데이터를 입력할 변수 선언
V_DEPT_ROW DEPT%ROWTYPE;
-- 명시적 커서 선언(Declaration)
CURSOR c1 (p_deptno DEPT.DEPTNO%TYPE) IS
SELECT DEPTNO, DNAME, LOC
FROM DEPT
WHERE DEPTNO = p_deptno;
BEGIN
-- 10번 부서 처리를 위해 커서 사용
OPEN c1 (10);
LOOP
FETCH c1 INTO V_DEPT_ROW;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('10번 부서 - DEPTNO : ' || V_DEPT_ROW.DEPTNO
|| ', DNAME : ' || V_DEPT_ROW.DNAME
|| ', LOC : ' || V_DEPT_ROW.LOC);
END LOOP;
CLOSE c1;
-- 20번 부서 처리를 위해 커서 사용
OPEN c1 (20);
LOOP
FETCH c1 INTO V_DEPT_ROW;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('20번 부서 - DEPTNO : ' || V_DEPT_ROW.DEPTNO
|| ', DNAME : ' || V_DEPT_ROW.DNAME
|| ', LOC : ' || V_DEPT_ROW.LOC);
END LOOP;
CLOSE c1;
END;
/
DECLARE
-- 사용자가 입력한 부서 번호를 저장하는 변수선언
v_deptno DEPT.DEPTNO%TYPE;
-- 명시적 커서 선언(Declaration)
CURSOR c1 (p_deptno DEPT.DEPTNO%TYPE) IS
SELECT DEPTNO, DNAME, LOC
FROM DEPT
WHERE DEPTNO = p_deptno;
BEGIN
-- INPUT_DEPTNO에 부서 번호 입력받고 v_deptno에 대입
v_deptno := &INPUT_DEPTNO;
-- 커서 FOR LOOP 시작. c1 커서에 v_deptno를 대입
FOR c1_rec IN c1(v_deptno) LOOP
DBMS_OUTPUT.PUT_LINE('DEPTNO : ' || c1_rec.DEPTNO
|| ', DNAME : ' || c1_rec.DNAME
|| ', LOC : ' || c1_rec.LOC);
END LOOP;
END;
/
BEGIN
UPDATE DEPT SET DNAME='DATABASE'
WHERE DEPTNO = 50;
DBMS_OUTPUT.PUT_LINE('갱신된 행의 수 : ' || SQL%ROWCOUNT);
IF (SQL%FOUND) THEN
DBMS_OUTPUT.PUT_LINE('갱신 대상 행 존재 여부 : true');
ELSE
DBMS_OUTPUT.PUT_LINE('갱신 대상 행 존재 여부 : false');
END IF;
IF (SQL%ISOPEN) THEN
DBMS_OUTPUT.PUT_LINE('커서의 OPEN 여부 : true');
ELSE
DBMS_OUTPUT.PUT_LINE('커서의 OPEN 여부 : false');
END IF;
END;
/
DECLARE
v_wrong NUMBER;
BEGIN
SELECT DNAME INTO v_wrong
FROM DEPT
WHERE DEPTNO = 10;
END;
/
- 예외처리:
PL/SQL 실행 중 예외가 발생했을 때 프로그램이 비정상 종료되는 것을 막기 위해 특정 명령어를 PL/SQL문 안에 작성하는 것- 예외처리는 PL/SQL문 안에서 EXCEPTION 영역에 필요 코드를 작성하는 것을 뜻한다.
DECLARE
v_wrong NUMBER;
BEGIN
SELECT DNAME INTO v_wrong
FROM DEPT
WHERE DEPTNO = 10;
EXCEPTION
WHEN VALUE_ERROR THEN
DBMS_OUTPUT.PUT_LINE('예외 처리 : 수치 또는 값 오류 발생');
END;
/
- 예외 처리부 또는 예외 처리절:
EXCEPTION 키워드 뒤에 예외 처리를 위해 작성된 코드 부분- 예외 처리부가 실행되면 예외가 발생한 코드 이후의 내용은 실행되지 않는다.
DECLARE
v_wrong NUMBER;
BEGIN
SELECT DNAME INTO v_wrong
FROM DEPT
WHERE DEPTNO = 10;
DBMS_OUTPUT.PUT_LINE('예외가 발생하면 다음 문장은 실행되지 않습니다');
EXCEPTION
WHEN VALUE_ERROR THEN
DBMS_OUTPUT.PUT_LINE('예외 처리 : 수치 또는 값 오류 발생');
END;
/
예외 종류 | 설명 | |
---|---|---|
내부 예외 | 사전 정의된 예외 | 내부 예외 중 예외 번호에 해당하는 이름이 존재하는 예외 |
내부 예외 | 이름이 없는 예외 | 내부 예외 중 이름이 존재하지 않는 예외(사용자가 필요에 따라 이름을 지정할 수 있음) |
사용자 정의 예외 | 사용자가 필요에 따라 직접 정의한 예외 |
EXCEPTION
WHEN 예외 이름 1 [OR 예외 이름2 - ] THEN
예외 처리에 사용할 명령어;
WHEN 예외 이름 3 [OR 예외 이름4 - ] THEN
예외 처리에 사용할 명령어;
...
WHEN OTHERS THEN
예외 처리에 사용할 명령어;
DECLARE
v_wrong NUMBER;
BEGIN
SELECT DNAME INTO v_wrong
FROM DEPT
WHERE DEPTNO = 10;
DBMS_OUTPUT.PUT_LINE('예외가 발생하면 다음 문장은 실행되지 않습니다');
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('예외 처리 : 요구보다 많은 행 추출 오류 발생');
WHEN VALUE_ERROR THEN
DBMS_OUTPUT.PUT_LINE('예외 처리 : 수치 또는 값 오류 발생');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('예외 처리 : 사전 정의 외 오류 발생');
END;
/
오류 처리부가 잘 작성되어 있다면 오류가 발생해도 PL/SQL은 정상 종료된다.
PL/SQL문의 정상 종료 여부와 상관없이 발생한 오류 내역을 알고 싶을 때 SQLCODE, SQLERRM 함수를 사용한다.
함수 | 설명 |
---|---|
SQLCODE | 오류 번호를 반환하는 함수 |
SQLERRM | 오류 메시지를 반환하는 함수 |
오류 코드와 오류 메시지 사용하기
DECLARE
v_wrong NUMBER;
BEGIN
SELECT DNAME INTO v_wrong
FROM DEPT
WHERE DEPTNO = 10;
DBMS_OUTPUT.PUT_LINE('예외가 발생하면 다음 문장은 실행되지 않습니다');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('예외 처리 : 사전 정의 외 오류 발생');
DBMS_OUTPUT.PUT_LINE('SQLCODE : ' || TO_CHAR(SQLCODE));
DBMS_OUTPUT.PUT_LINE('SQLERRM : ' || SQLERRM);
END;
/
-- 18-1
--①
DECLARE
-- 커서 데이터가 입력될 변수 선언
V_EMP_ROW EMP%ROWTYPE;
-- 명시적 커서 선언(Declaration)
CURSOR c1 IS
SELECT *
FROM EMP;
BEGIN
-- 커서 열기(Open)
OPEN c1;
LOOP
-- 커서로부터 읽어온 데이터 사용(Fetch)
FETCH c1 INTO V_EMP_ROW;
-- 커서의 모든 행을 읽어오기 위해 %NOTFOUND 속성지정
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('EMPNO : ' || V_EMP_ROW.EMPNO
|| ', ENAME : ' || V_EMP_ROW.ENAME
|| ', JOB : ' || V_EMP_ROW.JOB
|| ', SAL : ' || V_EMP_ROW.SAL
|| ', DEPTNO : ' || V_EMP_ROW.DEPTNO
);
END LOOP;
-- 커서 닫기(Close)
CLOSE c1;
END;
/
--②
DECLARE
-- 명시적 커서 선언(Declaration)
CURSOR c1 IS
SELECT *
FROM EMP;
BEGIN
-- 커서 FOR LOOP 시작 (자동 Open, Fetch, Close)
FOR c1_rec IN c1 LOOP
DBMS_OUTPUT.PUT_LINE('EMPNO : ' || c1_rec.EMPNO
|| ', ENAME : ' || c1_rec.ENAME
|| ', JOB : ' || c1_rec.JOB
|| ', SAL : ' || c1_rec.SAL
|| ', DEPTNO : ' || c1_rec.DEPTNO);
END LOOP;
END;
/
-- 18-2
DECLARE
v_wrong DATE;
BEGIN
SELECT ENAME INTO v_wrong
FROM EMP
WHERE EMPNO = 7369;
DBMS_OUTPUT.PUT_LINE('예외가 발생하면 다음 문장은 실행되지 않습니다');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('오류가 발생하였습니다.'
|| TO_CHAR(SYSDATE, '[YYYY"년"MM"월"DD"일" HH24"시"mm"분"SS"초"]'));
DBMS_OUTPUT.PUT_LINE('SQLCODE : ' || TO_CHAR(SQLCODE));
DBMS_OUTPUT.PUT_LINE('SQLERRM : ' || SQLERRM);
END;
/