프로그램 흐름 제어
명령문을 입력된 순서대로 실행하는 SQL과 달리 PL/SQL에는 프로그램 흐름을 제어할 수 있는 제어 명령문이 있습니다.
제어 명령문 정보
PL/SQL에는 조건부 선택 문, 루프 문 및 순차 제어문의 세 가지 제어문 범주가 있습니다.
조건부 선택 명령문 - 다른 데이터 값에 대해 서로 다른 명령문을 실행할 수 있습니다. 조건부 선택문은 IF 및 CASE입니다.
루프 명령문 - 일련의 다른 데이터 값에서 동일한 명령문을 반복할 수 있습니다. 루프 명령문은 FOR LOOP, WHILE LOOP 및 기본 LOOP입니다. EXIT 문은 제어권을 루프 끝으로 전달하고 CONTINUE 문은 루크의 현재 반복을 종료하고 다음 반복으로 제어권을 전달합니다. EXIT와 CONTINUE에는 모두 조건을 지정할 수 있는 선택적 WHEN 절이 있습니다.
순차적 제어 명령문 - 지정된 레이블이 있는 명령문으로 이동하거나 작업을 수행하지 않을 수 있습니다. 순차 제어문은 GOTO 및 NULL입니다.
참조: PL/SQL 제어문의 개요는 Oracle Database PL/SQL Language Reference
IF 문 사용
IF 문은 부울 표현식의 값에 따라 명령문 시퀀스를 실행하거나 건너뜁니다.
IF 문의 구문은 다음과 같습니다.
IF boolean_expression THEN statement [, statement ]
[ ELSIF boolean_expression THEN statement [, statement ] ]...
[ ELSE statement [, statement ] ]
END IF;
회사가 직원을 고용한 후 첫 10년 간은 매년 두 번씩 평가하지만 그 이후에는 매년 한 번만 평가한다고 가정합니다. 그래서 직원의 평가 빈도를 반환하는 함수가 필요합니다. IF 문을 사용하여 함수의 반환 값을 결정할 수 있습니다(예: Example 5-4).
EVAL_FREQUENCY 함수를 EMP_EVAL 패키지의 본문에 추가하고 사양에 추가하지 않습니다. EVAL_FREQUENCY는 사양에 없으므로 패키지의 로컬입니다. 즉, 패키지 외부에서 호출할 수는 없고 패키지의 다른 하위 프로그램에서만 호출될 수 있습니다.
참고: Example 5-4의 두번째 SELECT 문에서와 같이 SQL 문에서 PL/SQL 변수를 사용하는 경우 변수에 서브 프로그램 이름을 한정하여 테이블 열에 대해 오류가 발생하지 않도록 하십시오.
참조:
-
IF 문의 구문은 Oracle Database PL/SQL Language Reference입니다.
-
IF 문 사용에 대한 자세한 내용은 Oracle Database PL/SQL Language Reference를 참조하십시오.
함수의 반환 값을 결정하는 IF 문 예 5-4
FUNCTION eval_frequency (emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE)
RETURN PLS_INTEGER
AS
h_date EMPLOYEES.HIRE_DATE%TYPE;
today EMPLOYEES.HIRE_DATE%TYPE;
eval_freq PLS_INTEGER;
BEGIN
SELECT SYSDATE INTO today FROM DUAL;
SELECT HIRE_DATE INTO h_date
FROM EMPLOYEES
WHERE EMPLOYEE_ID = eval_frequency.emp_id;
IF ((h_date + (INTERVAL '120' MONTH)) < today) THEN
eval_freq := 1;
ELSE
eval_freq := 2;
END IF;
RETURN eval_freq;
END eval_frequency;
CASE 문 사용
CASE 문은 조건 시퀀스에서 선택하여 해당 명령문을 실행합니다.
단순 CASE 문은 단일 표현식을 평가하고 여러 잠재적 값과 비교합니다. 이 문의 구문은 다음과 같습니다.
CASE expression
WHEN value THEN statement
[ WHEN value THEN statement ]...
[ ELSE statement [, statement ]... ]
END CASE;
검색된 CASE 문은 여러 부울 표현식을 평가하고 값이 TRUE인 첫번째 표현품을 선택합니다. 검색된 CASE 문에 대한 자세한 내용은 Oracle Database PL/SQL Language Reference를 참조하세요.
팁: CASE 문이나 중첩 IF 문을 사용할 수 있는 경우 CASE 문을 사용하십시오. 이렇게 읽기도 쉬울 뿐더 아니라 더 효율적입니다.
직원을 매년 한 번만 평가하는 경우 EVAL_FREQUENCY 함수를 사용하여 JOB_ID에 따라 임금 인상을 제안하려고 한다고 가정합니다.
Example 5-5에 표시된 대로 EVAL_FREQUENCY 함수를 변경합니다. 문자열을 인쇄하는 프로시저 DBMS_OUTPUT.PUT_LINE에 대한 자세한 내용은 Oracle Database PL/SQL Packages and Types Reference을 참조하십시오.
인쇄할 문자열을 결정하는 5-5 CASE 문 예
FUNCTION eval_frequency (emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE)
RETURN PLS_INTEGER
AS
h_date EMPLOYEES.HIRE_DATE%TYPE;
today EMPLOYEES.HIRE_DATE%TYPE;
eval_freq PLS_INTEGER;
j_id EMPLOYEES.JOB_ID%TYPE;
BEGIN
SELECT SYSDATE INTO today FROM DUAL;
SELECT HIRE_DATE, JOB_ID INTO h_date, j_id
FROM EMPLOYEES
WHERE EMPLOYEE_ID = eval_frequency.emp_id;
IF ((h_date + (INTERVAL '12' MONTH)) < today) THEN
eval_freq := 1;
CASE j_id
WHEN 'PU_CLERK' THEN DBMS_OUTPUT.PUT_LINE(
'Consider 8% salary increase for employee # ' || emp_id);
WHEN 'SH_CLERK' THEN DBMS_OUTPUT.PUT_LINE(
'Consider 7% salary increase for employee # ' || emp_id);
WHEN 'ST_CLERK' THEN DBMS_OUTPUT.PUT_LINE(
'Consider 6% salary increase for employee # ' || emp_id);
WHEN 'HR_REP' THEN DBMS_OUTPUT.PUT_LINE(
'Consider 5% salary increase for employee # ' || emp_id);
WHEN 'PR_REP' THEN DBMS_OUTPUT.PUT_LINE(
'Consider 5% salary increase for employee # ' || emp_id);
WHEN 'MK_REP' THEN DBMS_OUTPUT.PUT_LINE(
'Consider 4% salary increase for employee # ' || emp_id);
ELSE DBMS_OUTPUT.PUT_LINE(
'Nothing to do for employee #' || emp_id);
END CASE;
ELSE
eval_freq := 2;
END IF;
RETURN eval_freq;
END eval_frequency;
참조:
-
CASE 문의 구문은 Oracle Database PL/SQL Language Reference를 참조하십시오
-
CASE 문을 사용하는 방법은Oracle Database PL/SQL Language Reference를 참조하십시오.
FOR LOOP 문 사용
FOR LOOP 문은 lower_bound에서 upper_bound 사이 범위의 각 정수에 대해 한 번씩 명령문 시퀀스를 반복합니다.
FOR LOOP의 구문은 다음과 같습니다.
FOR counter IN lower_bound..upper_bound LOOP
statement [, statement ]...
END LOOP;
LOOP 및 END LOOP 사이의 명령문에서 카운터를 사용할 수 있지만 그 값을 변경할 수는 없습니다.
봉급 인상을 제안만 하는 것이 아니라 EVAL_FREQUENCY 함수를 사용하여 5년 동안 매년 제안된 양만큼 증가할 경우 임금이 얼마가 되는지를 보고하려고 가정합니다.
Example 5-6에 표시된 대로 EVAL_FREQUENCY 함수를 변경합니다. 문자열을 인쇄하는 프로시저 DBMS_OUTPUT.PUT_LINE에 대한 자세한 내용은 Oracle Database PL/SQL Packages and Types Reference을 참조하십시오.
5년 후의 봉급을 계산하는 FOR LOOP 문 예 5-6
FUNCTION eval_frequency (emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE)
RETURN PLS_INTEGER
AS
h_date EMPLOYEES.HIRE_DATE%TYPE;
today EMPLOYEES.HIRE_DATE%TYPE;
eval_freq PLS_INTEGER;
j_id EMPLOYEES.JOB_ID%TYPE;
sal EMPLOYEES.SALARY%TYPE;
sal_raise NUMBER(3,3) := 0;
BEGIN
SELECT SYSDATE INTO today FROM DUAL;
SELECT HIRE_DATE, JOB_ID, SALARY INTO h_date, j_id, sal
FROM EMPLOYEES
WHERE EMPLOYEE_ID = eval_frequency.emp_id;
IF ((h_date + (INTERVAL '12' MONTH)) < today) THEN
eval_freq := 1;
CASE j_id
WHEN 'PU_CLERK' THEN sal_raise :=
0.08;
WHEN 'SH_CLERK' THEN sal_raise := 0.07;
WHEN 'ST_CLERK' THEN sal_raise := 0.06;
WHEN 'HR_REP' THEN sal_raise := 0.05;
WHEN 'PR_REP' THEN sal_raise := 0.05;
WHEN 'MK_REP' THEN sal_raise := 0.04;
ELSE NULL;
END CASE;
IF (sal_raise != 0) THEN
BEGIN
DBMS_OUTPUT.PUT_LINE('If salary ' || sal || ' increases by ' ||
ROUND((sal_raise * 100),0) ||
'% each year for 5 years, it will be:');
FOR i IN 1..5 LOOP
sal := sal * (1 + sal_raise);
DBMS_OUTPUT.PUT_LINE(ROUND(sal, 2) || ' after ' || i || ' year(s)');
END LOOP;
END;
END IF;
ELSE
eval_freq := 2;
END IF;
RETURN eval_freq;
END eval_frequency;
참조:
-
FOR LOOP 문의 구문은 Oracle Database PL/SQL Language Reference입니다.
-
FOR LOOP 문을 사용하는 방법에 대한 자세한 내용은 Oracle Database PL/SQL Language Reference를 참조하십시오
WHILE LOOP 문 사용
WHILE LOOP 문은 조건이 TRUE인 동안 명령문 시퀀스를 반복합니다.
WHILE LOOP 문의 구문은 다음과 같습니다.
WHILE condition LOOP
statement [, statement ]...
END LOOP;
주: LOOP와 END LOOP 사이의 명령문으로 인해 조건이 FALSE가 되지 않는 경우 WHILE LOOP 문은 무기한 실행됩니다.
EVAL_FREQUENCY 함수가 FOR LOOP 문 대신 WHILE LOOP 문을 사용하고 제안된 급여가 JOB_ID의 최대 급여를 초과하면 끝난다고 가정합니다.
Example 5-7에 표시된 대로 EVAL_FREQUENCY 함수를 변경합니다. 문자열을 인쇄하는 프로시저 DBMS_OUTPUT.PUT_LINE에 대한 자세한 내용은 Oracle Database PL/SQL Packages and Types Reference을 참조하십시오.
최대값까지 급여를 계산하는 5-7 WHILE LOOP 문 예
FUNCTION eval_frequency (emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE)
RETURN PLS_INTEGER
AS
h_date EMPLOYEES.HIRE_DATE%TYPE;
today EMPLOYEES.HIRE_DATE%TYPE;
eval_freq PLS_INTEGER;
j_id EMPLOYEES.JOB_ID%TYPE;
sal EMPLOYEES.SALARY%TYPE;
sal_raise NUMBER(3,3) := 0;
sal_max JOBS.MAX_SALARY%TYPE;
BEGIN
SELECT SYSDATE INTO today FROM DUAL;
SELECT HIRE_DATE, j.JOB_ID, SALARY, MAX_SALARY INTO h_date, j_id, sal, sal_max
FROM EMPLOYEES e, JOBS j
WHERE EMPLOYEE_ID = eval_frequency.emp_id AND JOB_ID = eval_frequency.j_id;
IF ((h_date + (INTERVAL '12' MONTH)) < today) THEN
eval_freq := 1;
CASE j_id
WHEN 'PU_CLERK' THEN sal_raise := 0.08;
WHEN 'SH_CLERK' THEN sal_raise := 0.07;
WHEN 'ST_CLERK' THEN sal_raise := 0.06;
WHEN 'HR_REP' THEN sal_raise := 0.05;
WHEN 'PR_REP' THEN sal_raise := 0.05;
WHEN 'MK_REP' THEN sal_raise := 0.04;
ELSE NULL;
END CASE;
IF (sal_raise != 0) THEN
BEGIN
DBMS_OUTPUT.PUT_LINE('If salary ' || sal || ' increases by ' ||
ROUND((sal_raise * 100),0) ||
'% each year, it will be:');
WHILE sal <= sal_max LOOP
sal := sal * (1 + sal_raise);
DBMS_OUTPUT.PUT_LINE(ROUND(sal, 2));
END LOOP;
DBMS_OUTPUT.PUT_LINE('Maximum salary for this job is ' || sal_max);
END;
END IF;
ELSE
eval_freq := 2;
END IF;
RETURN eval_freq;
END eval_frequency;
참조:
-
WHILE LOOP 문의 구문은 Oracle Database PL/SQL Language Reference를 참조하십시오
-
WHILE LOOP 문을 사용하는 방법에 대한 자세한 내용은 Oracle Database PL/SQL Language Reference를 참조하십시오
기본 LOOP 및 EXIT WHEN 문 사용
기본 LOOP 문은 명령문 시퀀스를 반복하며
기본 LOOP 문의 구문은 다음과 같습니다.
LOOP
statement [, statement ]...
END LOOP;
적어도 하나의 명령문은 EXIT 문이어야 합니다. 그렇지 않으면 LOOP 문이 무한히 실행됩니다.
EXIT WHEN 문(선택적 WHEN 절이 포함된 EXIT 문)은 조건이 TRUE일 때 루프를 종료하고 제어권을 루프 끝으로 전달합니다.
EVAL_FREQUENCY 함수에서 WHILE LOOP 문의 마지막 반복 시 마지막으로 계산되는 값은 일반적으로 최대 급여를 초과합니다.
Example 5-8과 같이 EXIT WHEN 문을 포함하는 기본 LOOP 문으로 WHILE LOOP 문을 변경합니다.
예제 5-8 EXIT WHEN 문 사용
FUNCTION eval_frequency (emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE)
RETURN PLS_INTEGER
AS
h_date EMPLOYEES.HIRE_DATE%TYPE;
today EMPLOYEES.HIRE_DATE%TYPE;
eval_freq PLS_INTEGER;
j_id EMPLOYEES.JOB_ID%TYPE;
sal EMPLOYEES.SALARY%TYPE;
sal_raise NUMBER(3,3) := 0;
sal_max JOBS.MAX_SALARY%TYPE;
BEGIN
SELECT SYSDATE INTO today FROM DUAL;
SELECT HIRE_DATE, j.JOB_ID, SALARY, MAX_SALARY INTO h_date, j_id, sal, sal_max
FROM EMPLOYEES e, JOBS j
WHERE EMPLOYEE_ID = eval_frequency.emp_id AND JOB_ID = eval_frequency.j_id;
IF ((h_date + (INTERVAL '12' MONTH)) < today) THEN
eval_freq := 1;
CASE j_id
WHEN 'PU_CLERK' THEN sal_raise := 0.08;
WHEN 'SH_CLERK' THEN sal_raise := 0.07;
WHEN 'ST_CLERK' THEN sal_raise := 0.06;
WHEN 'HR_REP' THEN sal_raise := 0.05;
WHEN 'PR_REP' THEN sal_raise := 0.05;
WHEN 'MK_REP' THEN sal_raise := 0.04;
ELSE NULL;
END CASE;
IF (sal_raise != 0) THEN
BEGIN
DBMS_OUTPUT.PUT_LINE('If salary ' || sal || ' increases by ' ||
ROUND((sal_raise * 100),0) ||
'% each year, it will be:');
LOOP
sal := sal * (1 + sal_raise);
EXIT WHEN sal > sal_max;
DBMS_OUTPUT.PUT_LINE(ROUND(sal,2));
END LOOP;
DBMS_OUTPUT.PUT_LINE('Maximum salary for this job is ' || sal_max);
END;
END IF;
ELSE
eval_freq := 2;
END IF;
RETURN eval_freq;
END eval_frequency;
참조:
-
명령문의 구문은 Oracle Database PL/SQL Language Reference를 참조하십시오.
-
EXIT 문의 구문은 Oracle Database PL/SQL Language Reference입니다.
-
LOOP 및 EXIT 문 사용에 대한 자세한 내용은 Oracle Database PL/SQL Language Reference를 참조하십시오.