251104 TIL
2025. 11. 4. 17:37ㆍCourses/아이티윌 오라클 DBA 과정
절차적 언어(Procedure Language)
- 함수나 모듈을 만들어서 문제에 대한 해결을 순서에 맞게 호출하여 수행하는 방식
PL/SQL(Procedure Language Structured Query Language)
- SQL을 확장한 절차적 언어(Procedure Language)
- 프로시저(procedure) 생성자 제공
- 변수, 상수, 데이터 유형(레코드, 배열)
- 조건문, 반복문
- 한 번 작성하여 여러 번 실행할 수 있는 재사용 가능한 프로그램 단위
PL/SQL 이점
모듈식 프로그램 개발
- 블록 내의 관련 명령문을 논리적으로 그룹화 할 수 있다.
- 블록을 더 큰 블록 내부에 중첩하여 강력한 프로그램을 작성할 수 있다.
- 코드를 쉽게 유지 관리 및 디버그 할 수 있다.
오라클 도구와 통합
- ERP, HR, CRM, SCM, …
이식성
- 운영체제나 플랫폼에 상관없이 오라클 서버가 실행되는 모든 환경에서 실행 가능
예외 처리
- 오류가 발생했을 경우 처리할 수 있음
익명(Anonymous) 블록 구조
- 객체 프로그램이 아님(데이터베이스에 저장되지 않음)
DECLARE(선택)
선언부분(변수, 상수, 명시적 커서, 사용자 정의 예외사항)
BEGIN(필수)
실행부분(SQL, 로직구현)
EXCEPTION(선택)
예외사항(실행부분에서 발생한 오류에 대한 처리)
END;(필수)
/
출력 기능 프로그램 : dbms_output.put_line
BEGIN
dbms_output.put_line('오늘 하루도 열심히 공부하자!!');
END;
/
SQL Developer 출력 설정

- 보기 > DBMS 출력

- + 버튼 클릭 → 접속 선택

- PL/SQL 실행
SQL*Plus 출력 설정

set serveroutput on
날짜 출력
BEGIN
dbms_output.put_line('today''s : ' || to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss'));
dbms_output.put_line('tomorrow''s : ' || to_char(sysdate + 1, 'yyyy-mm-dd hh24:mi:ss'));
END;
/
BEGIN
dbms_output.put_line(q'[today's : ]' || to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss'));
dbms_output.put_line(q'[tomorrow's : ]' || to_char(sysdate + 1, 'yyyy-mm-dd hh24:mi:ss'));
END;
/

변수
- 데이터를 임시로 저장하는 메모리 영역
- 문자로 시작해야 함
- 문자, 숫자, 특수문자(_, #, $) 포함 가능
- 변수명 길이는 30자 이하만 가능
- 예약어는 사용 불가
- 변수 선언시에 NOT NULL, CONSTANT(상수)로 지정된 변수에는 꼭 초기값을 할당해야 함
- 변수에 값을 할당하는 연산자 :
:=,default - 가독성 및 코드 유지 관리 효율을 높이기 위해서 각 행마다 하나씩 식별자(변수, 상수)를 선언
- 예) v_id, v_no number; → 오류 발생
- v_id number;
v_no number;
예약어 조회
SELECT *
FROM v$reserved_words
WHERE reserved = 'Y';

변수 출력
- 변수 선언 후 실행부에서 초기화
DECLARE
v_name varchar(30);
BEGIN
dbms_output.put_line('My name is ' || v_name);
v_name := 'james';
dbms_output.put_line('My name is ' || v_name);
END;
/

- 변수 선언 시 초기화
DECLARE
v_name varchar(30) := 'liam';
BEGIN
dbms_output.put_line('My name is ' || v_name);
v_name := 'james';
dbms_output.put_line('My name is ' || v_name);
END;
/

Scalar data type
DECLARE
/* scalar data type : 단일값만 보유하는 변수 */
v_a number(5);
v_b number(3) := 100;
v_c varchar2(10) NOT NULL := 'oracle';
v_d CONSTANT date default sysdate;
v_e CONSTANT number(3) := 20;
BEGIN
v_a := 200;
dbms_output.put_line(v_a);
dbms_output.put_line(v_b);
dbms_output.put_line(v_c);
dbms_output.put_line(v_d);
dbms_output.put_line(v_e);
END;
/
- 단일값만 보유하는 변수
CONSTANT: 상수- 다른 값으로 재할당 불가 → 오류 발생
Local Variable(지역 변수)
- 선언된 블록 프로그램에서만 수행하는 변수
DECLARE
/* local variable(지역변수) : 선언된 블록 프로그램에서만 수행하는 변수 */
v_sal number := 10000;
v_comm number := 1000;
v_total number;
BEGIN
v_total := v_sal + v_comm;
dbms_output.put_line(v_total);
END;
/
SELECT * FROM hr.employees WHERE salary > v_total;
-- v_total 변수는 local variable(지역 변수)이기 때문에 블록 프로그램 바깥쪽에서 사용 불가

Bind Variable(바인드 변수)
- 호스트 환경에서 생성(프로그램 바깥쪽에서 선언)
- 호스트 변수
variable(var)키워드를 사용해서 선언- 바인드변수는 SQL문과 PL/SQL 블록(익명 블록) 에서 사용 가능
- 바인드 변수를 사용할 때는 콜론(:) 키워드를 바인드 변수 앞에 붙여서 사용
- global variable(전역변수) 처럼 사용하고 싶을 때 사용
- global variable(전역변수) : 프로그램 어디서든지 사용하는 변수, 세션이 열려있는 동안에는 어디서든지 사용 가능
var b_total number
DECLARE
v_sal number := 10000;
v_comm number := 1000;
BEGIN
:b_total := v_sal + v_comm;
dbms_output.put_line(:b_total);
END;
/
print :b_total
print b_total
SELECT * FROM hr.employees WHERE salary > :b_total;

바인드 변수의 필요성
- Shared Pool 메모리 비우기
ALTER SYSTEM FLUSH SHARED_POOL;
- SQL 실행
SELECT * FROM hr.employees WHERE employee_id = 100;
- Shared Pool에 캐시된 SQL 커서 정보 조회
SELECT sql_id, sql_text, parse_calls, loads, executions, hash_value, plan_hash_value
FROM v$sql
WHERE sql_text like '%employees%'
AND sql_text not like '%v$sql%';

- PARSE_CALLS : 파싱 요청 횟수
- LOADS : 하드 파싱 횟수
- EXECUTIONS : 실행 횟수
- Soft Parsing이 발생하면 LOADS 는 증가하지 않음
SELECT * FROM hr.employees WHERE employee_id = 100;
SELECT * FROM hr.employees WHERE employee_id = 101;
SELECT * FROM hr.employees WHERE employee_id = 102;
SELECT * FROM hr.employees WHERE employee_id = 103;
SELECT * FROM hr.employees WHERE employee_id = 104;
SELECT * FROM hr.employees WHERE employee_id = 105;
SELECT sql_id, sql_text, parse_calls, loads, executions, hash_value, plan_hash_value
FROM v$sql
WHERE sql_text like '%employees%'
AND sql_text not like '%v$sql%';

- 리터럴 값을 사용할 경우 실행 계획을 공유하지 못하고 각각 하드 파싱이 발생함
- 메모리, CPU 사용량 증가
PLAN_HASH_VALUE가 같은 쿼리들은 실행 계획이 같은 쿼리이기 때문에 바인드 변수를 사용하면 실행계획 재사용 가능- 실행 계획 조회
SELECT * FROM table(dbms_xplan.display_cursor('fsg55tcss0s6m'));
SELECT * FROM table(dbms_xplan.display_cursor('7s0rxjt3f50a9'));
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 1 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 69 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 (0)| |
---------------------------------------------------------------------------------------------
- 바인드 변수 사용
SELECT * FROM hr.employees WHERE employee_id = :b_id;

- 여러 번 실행해도 하드 파싱 발생 X
SQL*Plus에서 바인드 변수 사용법

var키워드로 바인드 변수 선언execute(exec)로 바인드 변수 초기화
바인드 변수 선언시 주의점
- number 타입에는 사이즈를 지정하면 X

- 문자형에는 사이즈 지정해줘야 함 (지정 안 하면 1byte)

PL/SQL의 SQL 함수
프로시저 문에서 사용할 수 있는 함수
- 단일행 함수(decode, nvl2 제외)
DECLARE
v_last_name varchar2(10) := 'hong';
v_first_name varchar2(30) := 'gil dong';
BEGIN
dbms_output.put_line(upper(v_last_name));
dbms_output.put_line(initcap(v_first_name));
END;
/

DECLARE
v_last_name varchar2(10) := initcap('hong');
v_first_name varchar2(30) := initcap('gil dong');
BEGIN
dbms_output.put_line(v_last_name || ' ' || v_first_name);
END;
/

DECLARE
v_sal number := 10000;
v_comm number;
v_total number;
BEGIN
v_total := v_sal * 12 + v_sal * nvl(v_comm, 0) * 12;
dbms_output.put_line(v_total);
END;
/

DECLARE
v_sal number := 10000;
v_comm number := 0.1;
v_total number;
BEGIN
v_total := coalesce(v_sal * 12 + v_sal * v_comm * 12, v_sal * 12);
dbms_output.put_line(v_total);
END;
/

DECLARE
v_begin_date date := to_date('2025-01-01', 'yyyy-mm-dd');
v_end_date date := to_date('2025-11-04', 'yyyy-mm-dd');
BEGIN
dbms_output.put_line(v_end_date - v_begin_date);
dbms_output.put_line(trunc(months_between(v_end_date, v_begin_date)));
dbms_output.put_line(add_months(v_end_date, 4));
dbms_output.put_line(next_day(v_end_date, '금요일'));
dbms_output.put_line(last_day(v_end_date));
END;
/

프로시저 문에서 사용할 수 없는 함수
- decode, nvl2, 그룹 함수
중첩 블록
/* MAIN BLOCK, OUTER BLOCK */
DECLARE
v_outer_variable varchar2(30) := 'outer variable';
BEGIN
/* SUB BLOCK, INNER BLOCK */
DECLARE
v_inner_variable varchar2(30) := 'inner variable';
BEGIN
dbms_output.put_line(v_inner_variable);
dbms_output.put_line(v_outer_variable);
END;
-- dbms_output.put_line(v_inner_variable);
-- PLS-00201: identifier 'V_INNER_VARIABLE' must be declared
dbms_output.put_line(v_outer_variable);
END;
/

- sub block에서 선언된 v_inner_variable 변수는 main block에서 사용 불가 → 오류 발생
DECLARE
v_father_name varchar2(20) := 'Patrick';
v_date_of_birth date := to_date('1960-01-01', 'yyyy-mm-dd');
BEGIN
DECLARE
v_child_name varchar2(20) := 'Mike';
v_date_of_birth date := to_date('1990-01-01', 'yyyy-mm-dd');
BEGIN
dbms_output.put_line('Father''s Name : ' || v_father_name);
dbms_output.put_line('Date of Birth : ' || v_date_of_birth);
dbms_output.put_line('Child''s Name : ' || v_child_name);
dbms_output.put_line('Date of Birth : ' || v_date_of_birth);
END;
dbms_output.put_line('Father''s Name : ' || v_father_name);
dbms_output.put_line('Date of Birth : ' || v_date_of_birth);
END;
/

- main block과 sub block에 선언된 변수명이 동일할 경우 sub block 안에서는 sub block에서 선언된 변수의 우선순위가 더 높음
<<레이블>>
- 블록에 지정되는 이름
<<outer>>
DECLARE
v_father_name varchar2(20) := 'Patrick';
v_date_of_birth date := to_date('1960-01-01', 'yyyy-mm-dd');
BEGIN
DECLARE
v_child_name varchar2(20) := 'Mike';
v_date_of_birth date := to_date('1990-01-01', 'yyyy-mm-dd');
BEGIN
dbms_output.put_line('Father''s Name : ' || v_father_name);
dbms_output.put_line('Date of Birth : ' || outer.v_date_of_birth);
dbms_output.put_line('Child''s Name : ' || v_child_name);
dbms_output.put_line('Date of Birth : ' || v_date_of_birth);
END;
dbms_output.put_line('Father''s Name : ' || v_father_name);
dbms_output.put_line('Date of Birth : ' || v_date_of_birth);
END;
/

- 레이블 지정 후
레이블명.변수명으로 sub block 안에서 main block의 변수 사용 가능
<<outer>>
DECLARE
v_sal number := 60000;
v_comm number := v_sal * 0.2;
v_message varchar2(50) := 'eligible for commission';
BEGIN
DECLARE
v_sal number := 50000;
v_comm number := 0;
v_total number := v_sal + v_comm;
BEGIN
v_message := 'Clerk not ' || v_message;
outer.v_comm := v_sal * 0.3;
dbms_output.put_line('******* sub block *******');
dbms_output.put_line(v_sal);
dbms_output.put_line(v_comm);
dbms_output.put_line(v_total);
dbms_output.put_line(v_message);
END;
dbms_output.put_line('******* main block *******');
dbms_output.put_line(v_sal);
dbms_output.put_line(v_comm);
-- dbms_output.put_line(v_total);
dbms_output.put_line('Salesman ' || v_message);
END;
/

조건 제어문
- 조건에 따라 선별적으로 작업을 수행할 수 있음
- PL/SQL 블록 내에서 명령문의 논리적 흐름을 변경할 수 있음
- BOOLEAN은 참(TRUE), 거짓(FALSE)
IF문
- 조건을 평가하여 명령문을 수행
IF 조건 THEN
참
END IF;
IF 조건 THEN
참
ELSE
거짓
END IF;
IF 조건1 THEN
참
ELSIF 조건2 THEN
참
ELSIF 조건3 THEN
참
...
ELSE
거짓
END IF;
비교 연산자
- =, >, >=, <, <=, <>, !=, ^=
논리 연산자
- NOT, AND, OR
기타 비교 연산자
- IN,BETWEEN, LIKE
NULL 연산자
- IS NULL, IS NOT NULL
예시
- boolean형 변수 사용
DECLARE
v_flag boolean := true;
BEGIN
IF v_flag THEN
dbms_output.put_line('참');
END IF;
END;
/
DECLARE
v_flag boolean;
BEGIN
IF v_flag THEN
dbms_output.put_line('참');
ELSE
dbms_output.put_line('거짓');
END IF;
END;
/
- NULL 비교 연산자
DECLARE
v_num number;
BEGIN
IF v_num IS NULL THEN
dbms_output.put_line('참');
ELSE
dbms_output.put_line('거짓');
END IF;
END;
/
DECLARE
v_num number;
BEGIN
IF v_num IS NOT NULL THEN
dbms_output.put_line('참');
ELSE
dbms_output.put_line('거짓');
END IF;
END;
/
- 비교 연산자
DECLARE
v_num1 number := 10;
v_num2 number := 20;
BEGIN
IF v_num1 >= v_num2 THEN
dbms_output.put_line(v_num1 - v_num2);
ELSIF v_num1 < v_num2 THEN
dbms_output.put_line(v_num2 - v_num1);
END IF;
END;
/
- NVL2 함수 구현
DECLARE
v_sal number := :b_sal;
v_comm number := :b_comm;
v_annual_salary number;
BEGIN
IF v_comm IS NOT NULL THEN
v_annual_salary := v_sal * 12 + v_sal * v_comm * 12;
dbms_output.put_line(v_annual_salary);
ELSE
v_annual_salary := v_sal * 12;
dbms_output.put_line(v_annual_salary);
END IF;
END;
/
- decode 함수, IF문으로 조건에 따른 변수 초기화 불가
DECLARE
v_result char(1) := decode(); -- 오류 발생
BEGIN
v_result := IF ...; -- 오류 발생
END;
/
CASE 표현식
- 조건을 평가하여 값을 반환
DECLARE
v_grade char(1) := upper(:b_grade);
v_appraisal varchar2(30);
BEGIN
v_appraisal := CASE v_grade
WHEN 'A' THEN '참잘했어요'
WHEN 'B' THEN '잘했어요'
WHEN 'C' THEN '다음에 잘해요'
ELSE
'니가 사람이야!!'
END;
dbms_output.put_line('등급은 ' || v_grade || ' 평가는 ' || v_appraisal);
END;
/
DECLARE
v_grade char(1) := upper(:b_grade);
v_appraisal varchar2(30);
BEGIN
v_appraisal := CASE WHEN v_grade = 'A' THEN '참잘했어요'
WHEN v_grade IN ('B', 'C') THEN '잘했어요'
WHEN v_grade = 'D' THEN '다음에 잘해요'
ELSE
'니가 사람이야!!'
END;
dbms_output.put_line('등급은 ' || v_grade || ' 평가는 ' || v_appraisal);
END;
/
DECLARE
v_grade char(1) := upper(:b_grade);
v_appraisal varchar2(30);
BEGIN
IF v_grade = 'A' THEN
v_appraisal := '참잘했어요'
ELSIF v_grade IN ('B', 'C') THEN
v_appraisal := '잘했어요'
ELSIF v_grade = 'D' THEN
v_appraisal := '다음에 잘해요'
ELSE
v_appraisal := '니가 사람이야!!'
END IF;
dbms_output.put_line('등급은 ' || v_grade || ' 평가는 ' || v_appraisal);
END;
/
'Courses > 아이티윌 오라클 DBA 과정' 카테고리의 다른 글
| 251106 TIL (0) | 2025.11.06 |
|---|---|
| 251105 TIL (0) | 2025.11.05 |
| 251103 TIL (0) | 2025.11.03 |
| 251031 TIL (1) | 2025.10.31 |
| 251030 TIL (0) | 2025.10.30 |