2과목 SQL 기본 및 활용
- 20문제
- 각 상황별로 SQL문 작성이 가능할 정도로 연습해야 합니다.
- 기본적인 SQL문법 및 함수는 생략하고 Tuning에 활용될수 있는 것 위주로 정리하고자 합니다.
2장 SQL 활용 (#5)
PL/SQL (Procedural Language/SQL)
특징
- Block 구조로 되어 있어 각 기능별로 모듈화가 가능
- 변수, 상수 등을 선언하여 SQL 문장 간 값을 교환
- IF, LOOP 등의 절차형 언어를 사용하여 프로그램이 가능
- DBMS 정의 에러/사용자 정의 에러를 사용
- Oracle에 내장되어 있으므로 다른 Oracle Server로 옮길수 있음
- 여러 SQL문장을 Block으로 묶어서 한번에 서버로 보내기 때문에 통신량을 줄일수 있음
- Server에서 수행되므로 Application의 성능을 향상
구조
- DECLARE : BEGIN ~ END 사이에 변수, 인수에 대한 정의 및 데이터 타입 선언
- BEGIN : PL/SQL 시작
- EXCEPTION : BEGIN ~ END 에서 실행되는 SQL문에서 발생한 에러를 처리 (선택항목)
- END : PL/SQL 종료
문법 (Syntax)
- 생성
CREATE [OR REPLACE] PROCEDURE 명칭
{
argument1 [mode] data_type1,
argument2 [mode] data_type2,
...
}
IS [AS]
...
BEGIN
...
EXCEPTION
...
END;
/
- mode : IN (입력) , OUT (출력) , INOUT(입출력)
- 삭제
DROP PROCEDURE 명칭;
예제
DEPT table에 새로운 부서를 입력하는데,부서번호가 이미 존재하지 않을때만 입력하고 존재할 경우에는 그냥 종료되는 PROCEDURE를 작성해보자.
CREATE OR REPLACE PROCEDURE INPUT_DEPT
(
v_deptno in NUMBER,
v_dname in VARCHAR2,
v_loc in VARCHAR2,
v_result out VARCHAR2
)
IS
is_exist NUMBER := 0;
BEGIN
SELECT COUNT(*) INTO is_exist FROM DEPT WHERE DEPTNO = v_deptno AND ROWNUM = 1;
IF is_exist > 0 THEN
v_result := '이미 등록된 부서번호';
ELSE
INSERT INTO DEPT (DEPTNO, DNAME, LOC) VALUES (v_deptno, v_dname, v_loc);
COMMIT;
v_result := '입력 완료';
END IF;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
v_result := '에러 발생';
END;
/
실행을 시켜 보겠다.
EXECUTE INPUT_DEPT(10,'DEV','SEOUL',:result)
EXECUTE INPUT_DEPT(60,'NEW_DEV','SANGAM',:result)
User Defined Function
- Function는 Procedure와는 다르게 반드시 1개의 값을 RETURN해야 한다. (SUM, NVL 같은 내장 함수를 생각하면 이해가 쉽다.)
- ABS 함수 구현 : 절대값을 RETURN
CREATE OR REPLACE FUNCTION ABS_NUM
(v_input IN NUMBER)
RETURN NUMBER
IS
v_return NUMBER := 0;
BEGIN
if v_input >= 0 THEN
v_return := v_input;
ELSE
v_return := v_input * -1;
END IF;
RETURN v_return;
END;
/
SELECT ABS_NUM(-20), ABS_NUM(3) FROM DUAL;
Trigger
- 특정 Table에 DML (INSERT, UPDATE, DELETE)문이 수행했을 때 자동으로 동작 (사용자 실행이 아닌 DBMS가 실행)
- DBMS에서 실행을 하는 것이므로 DB에 바로 적용됨. (COMMIT, ROLLBACK이 불가)
- Syntax (문법)
CREATE [OR REPLACE] TRIGGER trigger_name -- TRIGGER 명칭
BEFORE | AFTER -- 아래 작업이 일어나기 전(BEFORE) 또는 후(AFTER)에 실행
INSERT | UPDATE | DELETE ON table_name -- 해당 table에 해당 작업이 일어났을 경우
[ FOR EACH ROW ] -- 행 트리거 (행 데이터 제어가능), 없으면 문장 트리거 (각 행 데이터 제어 불가)
[ WHEN (condition) ] -- 해당 조건에 맞을때에만 실행
PL/SQL block...
- 행의 데이터는
:NEW.column_name
,:OLD.column_name
으로 제어가 가능하다.- INSERT :
:NEW
(입력되는 ROW) - UPDATE :
:NEW
(변경된 새로운 값),:OLD
(변경 전의 값) - DELTE :
:OLD
(삭제된 값)
- INSERT :
- 예
쇼핑몰의 경우
- 하루 수만건의 주문이 들어옴
- 직원들은 일자별, 상품별 총 판매수량 및 주문실적으로 온라인으로 조회함
이럴 경우 매번 수만건의 데이터로 집계를 낼려면 서버 부하가 크다.
Trigger를 이용하여 주문이 들어올 때마다 집계를 계산하여 별도 Table에 보관하면 된다.
Trigger를 이용하여 주문이 들어올 때마다 집계를 계산하여 별도 Table에 보관하면 된다.
- Table 생성
CREATE TABLE ORDER_LIST
(
ORDER_DATE CHAR(8) NOT NULL,
PRODUCT VARCHAR2(10) NOT NULL,
QTY NUMBER NOT NULL,
AMOUNT NUMBER NOT NULL
);
CREATE TABLE SALES_PER_DATE
(
SALE_DATE CHAR(8) NOT NULL,
PRODUCT VARCHAR2(10) NOT NULL,
QTY NUMBER NOT NULL,
AMOUNT NUMBER NOT NULL
);
- Trigger 생성
CREATE OR REPLACE TRIGGER SUM_SALES
AFTER INSERT
ON ORDER_LIST -- ORDER_LIST table에 INSERT 작업 후에
FOR EACH ROW -- 행 트리거로 실행
DECLARE
o_date ORDER_LIST.ORDER_DATE%TYPE;
o_prod ORDER_LIST.PRODUCT%TYPE;
BEGIN
o_date := :NEW.ORDER_DATE;
o_prod := :NEW.PRODUCT;
UPDATE SALES_PER_DATE
SET QTY = QTY + :NEW.QTY,
AMOUNT = AMOUNT + :NEW.AMOUNT
WHERE SALE_DATE = o_date
AND PRODUCT = o_prod;
IF SQL%NOTFOUND THEN
INSERT INTO SALES_PER_DATE
VALUES (o_date, o_prod, :NEW.QTY, :NEW.AMOUNT);
END IF;
END;
/
- 데이터 입력 및 결과 확인
INSERT INTO ORDER_LIST VALUES ('20160127','Orange', 2, 10000);
INSERT INTO ORDER_LIST VALUES ('20160127','Orange', 5, 20000);
INSERT INTO ORDER_LIST VALUES ('20160127','PetaSQL', 1, 100);
INSERT INTO ORDER_LIST VALUES ('20160127','ChakraMAX', 1, 1000);
SELECT * FROM ORDER_LIST;
SELECT * FROM SALES_PER_DATE;
댓글 없음:
댓글 쓰기