Part2. 데이터베이스 프로그래머
Chapter 05. 데이터베이스 프로그래밍
데이터베이스 프로그래밍 방법
데이터베이스 프로그래밍은 DBMS에 데이터를 정의하고 저장된 데이터를 읽어 와 데이터를 변경하는 프로그램을 작성하는 과정이며, SQL을 포함한다는 점이 일반 프로그래밍과는 다르다.
PL/SQL
PL/SQL은 Procedural Language/Structured Query Language의 줄임말로, 데이터베이스 응용프로그램을 작성하는 데 사용하는 오라클의 SQL 전용 언어이다. SQL Developer에서 바로 작성하고 컴파일 한 후 결과를 실행한다. PL/SQL로 개발한 프로그램은 SQL Developer에 프로시저로 저장할 수 있으며 나중에 필요할때마다 호출하여 사용할 수 있다.
SQL 언어를 확장하여 데이터베이스 전용 응용 프로그램을 작성할 때 사용하는 오라클사의 SQL 전용 언어이다.
프로시저
PL/SQL은 프로그램 로직을 프로시저로 구현하여 객체 형태로 사용한다. 프로시저는 일반 프로그래밍 언어에서 사용하는 함수와 비슷한 개념으로, 작업 순서가 정해진 독립된 프로그램의 수행 단위를 말한다. 프로시저는 CREATE PROCEDURE문을 사용해 정의한다.
PL/SQL에서 사용하는 기능으로, 일반프로그래밍 언어의 함수 대신 사용하는 명칭이다. 프로시저를 정의하여 DBMS에 저장한다.
- PL/SQL은 선언부()와 실행부(BEGIN-END){}로 구성된다. 선언부에서는 변수와 매개변수를 선언하고 실행부에서는 프로그램 로직을 구현한다.
- 매개변수는 저장 프로시저가 호출될 때 그 프로시저에 전달되는 값이다.
- 변수는 저장 프로시저나 트리거 내에서 사용되는 값이다.
삽입을 작업하는 프로시저
예제 5-1) Book 테이블에 한 개의 투플을 삽입하는 프로시저를 작성하시오.
(프로시저는 없으면 만들고 있으면 재정의하라(대체))
CREATE OR REPLACE PROCEDURE InsertBook( //프로시저 정의. 혹은 기존의 프로시저가 있으면 삭제하고 재정의한다.
myBookID IN NUMBER, //프로시저 매개변수 정의. IN은 입력인자, OUT은 출력인자
myBookName IN VARCHAR2, //프로시저 매개변수 정의
myPublisher IN VARCHAR2, //프로시저 매개변수 정의
myPrice IN NUMBER) //프로시저 매개변수 정의
AS
BEGIN
INSERT INTO Book(bookid, bookname, publisher, price)
VALUES(myBookID, myBookName, myPublisher, myPrice);
END;
/
EXEC InsertBook(13, '스포츠과학', '마당과학서적', 25000); //정의된 InsertBook 프로시저를 EXEC 문으로 호출하여 실행하면 Book테이블에 bookid가 13인 새로운 투플 한 개가 추가된다.
SELECT * FROM book;
제어문을 사용하는 프로시저
예제5-2) 동일한 도서가 있는지 점검 한 후 삽입하는 프로시저를 작성하시오
CREATE OR REPLACE PROCEDURE BookInsertOrUpdate( //프로시저 이름과 매개변수 정의. IN/OUT을 생략하면 기본값은 IN으로 설정
myBookID NUMBER, //위와동일
myBookName VARCHAR2, //위와동일
myPublisher VARCHAR2, //위와동일
myPrice INT) //위와동일
AS
mycount NUMBER; //지역변수 mycount선언
BEGIN
SELECT count (*) INTO mycount FROM Book //myBookName과 같은 이름의 책이 몇권 있는지 확인하여 mycount 변수에 값 저장
WHERE bookname LIKE mybookName; //위와 동일
IF mycount !=0 THEN //if조건문으로 삽입하려는 도서이름(myBookName)과 같은 도서가 있는지 확인하여, 있으면 가격(price)만 새로운가격(myprice)로 수정하고 아니면 투플 전체를 새로 삽입한다.
UPDATE Book SET price = myPrice //위와동일
WHERE bookname LIKE myBookName; //위와동일
ELSE //위와동일
INSERT INTO Book(bookid, bookname, publisher, price) //위와동일
VALUES(myBookID, myBookname, myPublisher, myPrice); //위와동일
END IF; //위와동일
END;
/
EXEC BookInsertOrUpdate(15, '스포츠 즐거움', '마당과학서적', 25000); //호출결과 Book테이블에 bookid가 15인 새로운 투플 한 개가 추가된다
SELECT * FROM Book;
EXEC BookInsertOrUpdate(15, '스포츠 즐거움', '마당과학서적', 20000); //호출결과 이미 같은 책 제목이 있으므로 가격만 변경된다
SELECT * FROM Book;
결과를 반환하는 프로시저
예쩨5-3) Book 테이블에 저장된 도서의 평균가격을 반환하는 프로시저를 작성하시오.
CREATE OR REPLACE PROCEDURE AveragePrice(
AverageVal OUT NUMBER) //OUT은 출력 매개변수라는 의미이다
AS
BEGIN
SELECT AVG(price) INTO AverageVal FROM Book WHERE price IS NOT NULL; //책의 평균값을 계산하여 매개변수 AverageVal에 저장. INTO문은 변수에 값을 저장할 때 사용한다.
END;
/
SET SERVEROUTPUT ON;
DECLARE
AverageVal NUMBER(6,1); //변수 AverageVal을 정의하였고 AveragePrice를 호출하였다. 호출 후 결과는 매개변수 AverageVal에 저장된다.
BEGIN
AveragePrice(AverageVal);
DBMS_OUTPUT.PUT_LINE('책값 평균 :'||AverageVal); //위 두번째에서 OUT했기때문에 출력가능. AverageVal 값을 출력하는 문장이다.
END;
커서를 사용하는 프로시저
커서는 실행 결과 테이블을 한 번에 한 행씩 처리하기 위하여 테이블의 행을 순서대로 가리키는 데 사용하는 포인터를 말한다. 커서와 관련된 키워드로는 CURSOR, OPEN, FETCH, CLOSE 등이 있다.
예제 5-4) Orders 테이블의 판매 도서에 대한 이익을 계산하는 프로시저를 작성하시오.
CREATE OR REPLACE PROCEDURE Interest
AS
myInterest NUMERIC;
Price NUMERIC;
CURSOR InterestCursor IS SELECT saleprice FROM Orders; //InterestCursor라는 이름의 CURSOR변수를 선언했다. InterestCursor는 SELECT 문의 결과 테이블을 차례대로 가리키는 포인터로 맨 처음에는 첫 번째 투플을 가리킨다.
BEGIN
myInterest :=0.0;
OPEN InterestCursor; //커서의 사용을 알리는(OPEN) 문장이다.
LOOP //LOOP반복분이며 EXIT WHEN문장에서 NOTFOUND조건을 만족하면 빠져나온다.
FETCH InterestCursor INTO Price; //다음 투플을 가져오는 FETCH문이다.
EXIT WHEN InterestCursor%NOTFOUND;
IF Price >= 30000 THEN //IF 조건에 따라 이익금을 myInterest에 저장한다.
myInterest := myInterest + Price * 0.1; //위와동일
ELSE //위와동일
myInterest := myInterest + Price *0.05; //위와동일
END IF; //위와동일
END LOOP;
CLOSE InterestCursor; //커서의 사용을 끝내는 CLOSE문이다.
DBMS_OUTPUT.PUT_LINE(' 전체 이익 금액 = '||myInterest); //myInterest의 결과값 출력
END;
/
SET SERVEROUTPUT ON; //정의된 프로시저 호출하며 매개변수 없이 바로 호출된다. 실행 결과는 도서의 판매 이익금이다.
EXEC Interest; //위와동일
트리거
트리거는 데이터의 변경(INSERT, DELETE, UPDATE)문이 실행될 때 자동으로 같이 실행되는 프로시저를 말한다. 보통 트리거는 데이터 변경문이 처리되는 세가지 지점, 즉 실행 전(BEFORE), 대신하여(INSTEAD OF), 실행 후(AFTER)에 동작한다. 오라클은 기본적으로 BEFORE와 AFTER를 제공한다.
예를들어 Book 테이블에 새로운 도서를 삽입 할 때 삽입된 내용을 백업하기 위해 다른 테이블 Book_log에 삽입된 내용을 기록한다고 하자. Book 테이블에 INSERT 문을 수행하면서 같이 실행할 수도 있지만, 사용자로서는 번거롭기도하고 보안상 백업을 감추어야 할 경우도 있다. 이때 트리거를 사용하면 편하다.
예제5-5) 신규 도서를 삽입 한 후 자동으로 Book_log 테이블에 삽입한 내용을 기록하는 트리거
먼저 실습을 위해 Book_log 테이블을 다음과 같이 생성한다
create table Book_log(
bookid_l NUMBER,
bookname_l VARCHAR2(40),
publisher_l VARCHAR2(40),
price_l NUMBER);
CREATE OR REPLACE TRIGGER AfterInsertBook
AFTER INSERT ON Book FOR EACH ROW //트리거가Book테이블에 INSERT 문이 실행되면 자동으로 실행된다는 의미이다.
DECLARE
average NUMBER;
BEGIN
INSERT INTO Book_log //Book에 삽입된 투플을 다시 한 번 Book_log 테이블에 저장하는 INSERT 문을 실행하라는 의미이다. 변수 앞에 :new는 새로 삽입될 투플의 값을 가리키는 지정자이다.
VALUES(:new.bookid, :new.bookname, :new.publisher, :new.price);
DBMS_OUTPUT.PUT_LINE('삽입 투플을 Book_log 테이블에 백업..'); //메세지를 출력하는 문장이다.
END;
/
INSERT INTO Book VALUES(14, '스포츠 과학 1', '이상미디어', 25000); //새로운 투플을 Book_log에 삽입하는 문장이다.
select * FROM Book WHERE BOOKID='14'; //Book 테이블에 삽입된 내용을 확인한다.
SELECT * FROM Book_log WHERE BOOKID_L='14'; //Book_log 테이블에 삽입된 내용을 확인한다.
사용자 정의 함수
예제 5-6) 판매된 도서에 대한 이익을 계산하는 함수를 작성하시오.
판매된 도서의 이익을 계산하기 위해 각 주문 건별로 실제 판매가격인 saleprice를 입력받아 가격에 맞는 이익(30,000원 이상이면 10%, 30,000원 미만이면 5%)을 계산하여 반환하는 함수를 작성해보자.
CREATE OR REPLACE FUNCTION fnc_Interest(
Price NUMBER) RETURN INT //매개변수
IS
myInterest NUMBER; //변수
BEGIN
IF Price >= 30000 THEN myInterest := Price*0.1;
ELSE myInterest := Price *0.05;
END IF;
RETURN myInterest;
END;
/
SELECT custid, orderid, saleprice, fnc_Interest(saleprice) interest
FROM Orders;
| 구분 | 프로시저 | 트리거 | 사용자 정의 함수 |
|---|---|---|---|
| 공통점 | 저장 프로시저임, 오라클의 경우 PL/SQL로 작성 | 저장 프로시저임, 오라클의 경우 PL/SQL로 작성 | 저장 프로시저임, 오라클의 경우 PL/SQL로 작성 |
| 정의방법 | CREATE PROCEDURE문 | CREATE TRIGGER문 | CREATE FUNCTION문 |
| 호출 방법 | EXEC 문으로 직접 호출 | INSERT, DELETE, UPDATE 문이 실행될 때 자동으로 실행됨 | SELECT 문으로 호출 |
| 기능의 차이 | SQL문으로 할 수 없는 복잡한 로직을 수행 | 기본값 제공, 데이터 제약 준수, SQL 뷰의 수정, 참조 무결성 작업 등을 수행 | 속성값을 가공하여 반환, SQL문에서 직접 사용 |
Comments