일반적으로 프로그래밍과 차이가 있지만, 오라클 내부에서 적절한 처리를 위해서 적용해 줄 수 있는 절차지향적 코드 작성 방식이다.
쿼리문의 집합으로 어떠한 동작을 일괄처리 하기 위한 용도로 사용한다.
SET SERVEROUTPUT ON; -- 출력문 활성화
DECLARE -- 변수를 선언하는 구간(선언부)
emp_num NUMBER;
BEGIN -- 대입/출력문/기타등등 코드를 실행하는 시작구간(실행부)
emp_num := 10;
dbms_output.put_line(emp_num); -- 출력문
dbms_output.put_line('hello PL/SQL');
-- [EXCEPTION] 옵션
END; -- PL/SQL이 끝나는 구간(종료)
-- 연산자
-- 일반 SQL문의 모든 연산자의 사용이 가능하고
-- **는 제곱을 의미한다.
DECLARE
A NUMBER := 2**2*3**2;
BEGIN
DBMS_OUTPUT.PUT_LINE('a = ' || TO_CHAR(A));
END;
DML문
DDL문은 사용이 불가능하다.
SELECT절 아래에 INTO절을 사용해 변수에 할당할 수 있다.
DECLARE
v_emp_name VARCHAR2(50); -- 사원명 변수 (문자열 변수는 길이제약이 필수 / 기본값이 없기 때문이다.)
v_dep_name VARCHAR2(50); -- 부서명 변수
BEGIN
SELECT
e.first_name,
d.department_name
INTO
v_emp_name, v_dep_name -- 변수에 대입을 의미
FROM employees e
LEFT OUTER JOIN departments D
ON e.department_id = d.department_id
WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE(v_emp_name || '-' || v_dep_name);
END;
DECLARE
v_emp_name employees.first_name%TYPE;
v_emp_email employees.email%TYPE;
BEGIN
SELECT
first_name, email
INTO
v_emp_name, v_emp_email
FROM employees
WHERE employee_id = 201;
DBMS_OUTPUT.PUT_LINE(v_emp_name || ': ' || v_emp_email);
END;
문제3. 사원 테이블에서 사원번호가 제일 큰 사원을 찾아낸 뒤, 해당 번호 + 1번으로 아래의 사원을 emps에 employee_id, last_name, email, hire_date, job_id를 신규 입력하는 익명 블록 만들기 SELECT절 이후에 INSERT문 사용이 가능하다.
/*
<사원명>: steven
<이메일>: stevenjobs
<입사일자>: 오늘날짜
<JOB_ID>: CEO
*/
DROP TABLE emps;
CREATE TABLE emps AS (SELECT * FROM employees WHERE 1 = 2);
DECLARE
v_max_empno employees.employee_id%TYPE;
BEGIN
SELECT MAX(employee_id)
INTO v_max_empno
FROM employees;
INSERT INTO emps
(employee_id, last_name, email, hire_date, job_id)
VALUES
(v_max_empno + 1, 'steven', 'stevenjobs', sysdate, 'CEO');
END;
SELECT * FROM emps;
IF문
DECLARE
v_num1 NUMBER := 10;
v_num2 NUMBER := 5;
BEGIN
IF
v_num1 >= v_num2
THEN
DBMS_OUTPUT.PUT_LINE(v_num1 || '이(가) 큰 수');
ELSE
DBMS_OUTPUT.PUT_LINE(v_num2 || '이(가) 큰 수');
END IF;
END;
ELSIF문
DECLARE
v_salary NUMBER := 0;
v_department_id NUMBER := 0;
BEGIN
v_department_id := ROUND(DBMS_RANDOM.VALUE(10, 120), -1);
SELECT salary
INTO v_salary
FROM employees
WHERE department_id = v_department_id
AND ROWNUM = 1; -- 첫째 값만 구해서 변수에 저장
DBMS_OUTPUT.PUT_LINE(v_salary);
IF v_salary <= 5000 THEN
DBMS_OUTPUT.PUT_LINE('낮음');
ELSIF v_salary <= 9000 THEN
DBMS_OUTPUT.PUT_LINE('중간');
ELSE
DBMS_OUTPUT.PUT_LINE('높음');
END IF;
END;
CASE 문
DECLARE
v_salary NUMBER := 0;
v_department_id NUMBER := 0;
BEGIN
v_department_id := ROUND(DBMS_RANDOM.VALUE(10, 120), -1);
SELECT salary
INTO v_salary
FROM employees
WHERE department_id = v_department_id
AND ROWNUM = 1;
DBMS_OUTPUT.PUT_LINE(v_salary);
CASE
WHEN v_salary <= 5000 THEN
DBMS_OUTPUT.PUT_LINE('낮음');
WHEN v_salary <= 9000 THEN
DBMS_OUTPUT.PUT_LINE('중간');
ELSE
DBMS_OUTPUT.PUT_LINE('높음');
END CASE;
END;
중첩 IF문
DECLARE
v_salary NUMBER := 0;
v_department_id NUMBER := 0;
v_commission NUMBER := 0;
BEGIN
v_department_id := ROUND(DBMS_RANDOM.VALUE(10, 120), -1);
SELECT salary, commission_pct
INTO v_salary, v_commission
FROM employees
WHERE department_id = v_department_id
AND ROWNUM = 1;
DBMS_OUTPUT.PUT_LINE(v_salary);
IF v_commission > 0 THEN
IF v_commission > 0.15 THEN
DBMS_OUTPUT.PUT_LINE(v_salary * v_commission);
END IF;
ELSE
DBMS_OUTPUT.PUT_LINE(v_salary);
END IF;
END;
WHILE 문
DECLARE
v_num NUMBER := 3;
v_count NUMBER := 1;
BEGIN
WHILE v_count <= 10
LOOP
DBMS_OUTPUT.PUT_LINE(v_num);
v_count := v_count + 1;
END LOOP;
END;
탈출문
DECLARE
v_num NUMBER := 3;
v_count NUMBER := 1;
BEGIN
WHILE v_count <= 10
LOOP
DBMS_OUTPUT.PUT_LINE(v_num);
EXIT WHEN v_count = 5;
v_count := v_count + 1;
END LOOP;
END;
FOR 문
DECLARE
v_num NUMBER := 3;
BEGIN
FOR i IN 1..10 -- .을 두개 작성해서 범위를 표현
LOOP
DBMS_OUTPUT.PUT_LINE(v_num || ' x ' || i || ' = ' || v_num * i);
END LOOP;
END;
CONTINUE문
DECLARE
v_num NUMBER := 3;
BEGIN
FOR i IN 1..10
LOOP
CONTINUE WHEN i = 5;
DBMS_OUTPUT.PUT_LINE(v_num || ' x ' || i || ' = ' || v_num * i);
END LOOP;
END;
PL/SQL Quiz02
문제1. 모든 구구단을 출력하는 익명 블록 만들기 (2 ~ 9단)
BEGIN
FOR i IN 2..9
LOOP
DBMS_OUTPUT.PUT_LINE('구구단: ' || i || '단');
FOR j in 1..9
LOOP
DBMS_OUTPUT.PUT_LINE(i || ' x ' || j || ' = ' || i * j);
END LOOP;
DBMS_OUTPUT.PUT_LINE('----------------------');
END LOOP;
END;
문제2. INSERT를 300번 실행하는 익명 블록 처리하기 board라는 이름의 테이블을 만들기 (bno writer title 컬럼 존재) bno는 SEQUENCE로 올리고 writer와 title에 번호를 붙여서 INSERT 진행 ex) 1, test1, title1 -> 2, test2, title2 -> 3, test3, title3 ...
CREATE TABLE board(
bno NUMBER PRIMARY KEY,
writer VARCHAR2(30),
title VARCHAR2(30)
);
CREATE SEQUENCE b_seq
START WITH 1
INCREMENT BY 1
MAXVALUE 1000
NOCYCLE
NOCACHE;
DECLARE
v_num NUMBER := 1;
BEGIN
WHILE v_num <= 300
LOOP
INSERT INTO board
VALUES (b_seq.NEXTVAL, 'test' || v_num, '제목제목' || v_num);
v_num := v_num + 1;
END LOOP;
COMMIT;
END;
SELECT * FROM board
ORDER BY bno desc;
Procedure
void 메서드와 유사하다.
특정한 로직을 처리하고 결과값을 반환하지 않는 코드 덩어리 (쿼리)
PL/SQL에도 값을 전달 받아서 코드를 실행 후 리턴하는 함수
프로시저를 통해서 값을 리턴하는 방법이 있다.
-- 매개값(인수) 없는 프로시저
CREATE PROCEDURE p_test
IS -- 선언부
v_msg VARCHAR2(30) := 'hello procedure';
BEGIN -- 실행부
DBMS_OUTPUT.PUT_LINE(v_msg);
END; -- 끝
EXEC p_test; -- 프로시저 호출문
-- IN 입력값을 받는 파라미터
CREATE PROCEDURE my_new_job_proc
(p_job_id IN jobs.job_id%TYPE,
p_job_title IN jobs.job_title%TYPE,
p_min_sal IN jobs.min_salary%TYPE,
p_max_sal IN jobs.max_salary%TYPE
)
IS
BEGIN
INSERT INTO jobs (job_id, job_title, min_salary, max_salary)
VALUES (p_job_id, p_job_title, p_min_sal, p_max_sal);
COMMIT;
END;
EXEC my_new_job_proc('JOB1', 'test job1', 1000, 5000);
job_id가 primary key인데 unique 제약조건을 위반하기 때문에 에러가 발생한다.
-- 이미 존재한다면 ALTER(수정), 없다면 CREATE(생성)
CREATE OR REPLACE PROCEDURE my_new_job_proc
(p_job_id IN jobs.job_id%TYPE,
p_job_title IN jobs.job_title%TYPE,
p_min_sal IN jobs.min_salary%TYPE,
p_max_sal IN jobs.max_salary%TYPE
)
IS
v_cnt NUMBER := 0;
BEGIN
-- 동일한 job_id가 있는지 체크
-- 이미 존재한다면 1, 존재하지 않는다면 0 -> v_cnt에 들어있다.
SELECT COUNT(*)
INTO v_cnt
FROM jobs
WHERE job_id = p_job_id;
IF v_cnt = 0 THEN -- 없다면 INSERT
INSERT INTO jobs (job_id, job_title, min_salary, max_salary)
VALUES (p_job_id, p_job_title, p_min_sal, p_max_sal);
ELSE -- 있다면 UPDATE
UPDATE jobs
SET job_title = p_job_title,
min_salary = p_min_sal,
max_salary = p_max_sal
WHERE job_id = p_job_id;
END IF;
COMMIT;
END;
EXEC my_new_job_proc('JOB1', 'test job1', 2000, 8000);
EXEC my_new_job_proc('JOB2', 'test job2'); -- 에러
-- 매개변수(인수)의 디폴트 값(기본값) 설정
CREATE OR REPLACE PROCEDURE my_new_job_proc
(p_job_id IN jobs.job_id%TYPE,
p_job_title IN jobs.job_title%TYPE,
p_min_sal IN jobs.min_salary%TYPE := 0,
p_max_sal IN jobs.max_salary%TYPE := 1000
)
IS
v_cnt NUMBER := 0;
BEGIN
-- 동일한 job_id가 있는지 체크
-- 이미 존재한다면 1, 존재하지 않는다면 0 -> v_cnt에 들어있다.
SELECT COUNT(*)
INTO v_cnt
FROM jobs
WHERE job_id = p_job_id;
IF v_cnt = 0 THEN -- 없다면 INSERT
INSERT INTO jobs (job_id, job_title, min_salary, max_salary)
VALUES (p_job_id, p_job_title, p_min_sal, p_max_sal);
ELSE -- 있다면 UPDATE
UPDATE jobs
SET job_title = p_job_title,
min_salary = p_min_sal,
max_salary = p_max_sal
WHERE job_id = p_job_id;
END IF;
COMMIT;
END;
EXEC my_new_job_proc('JOB2', 'test job2');
SELECT * FROM jobs
WHERE job_id = 'JOB2';
OUT, IN OUT 매개변수(인수) 사용
OUT 변수를 사용하면 프로시저 바깥으로 값을 보낸다.
OUT을 이용해서 보낸 값은 바깥 익명블록에서 실행해야 한다.
CREATE OR REPLACE PROCEDURE my_new_job_proc
(p_job_id IN jobs.job_id%TYPE,
p_job_title IN jobs.job_title%TYPE,
p_min_sal IN jobs.min_salary%TYPE := 0,
p_max_sal IN jobs.max_salary%TYPE := 1000,
p_result OUT VARCHAR2 -- 바깥쪽에서 출력하기 위한 변수
)
IS
v_cnt NUMBER := 0;
v_result VARCHAR(100) := '값이 없어서 insert 처리 되었습니다.';
BEGIN
SELECT COUNT(*)
INTO v_cnt
FROM jobs
WHERE job_id = p_job_id;
IF v_cnt = 0 THEN -- 없다면 INSERT
INSERT INTO jobs (job_id, job_title, min_salary, max_salary)
VALUES (p_job_id, p_job_title, p_min_sal, p_max_sal);
ELSE -- 있다면 결과를 추출
SELECT p_job_id || '의 최대 연봉: ' || max_salary || ', ' || '최소연봉: ' || min_salary
INTO v_result -- 조회 결과를 대입
FROM jobs
WHERE job_id = p_job_id;
END IF;
-- OUT 매개변수에 결과를 할당
p_result := v_result;
END;
DECLARE
str VARCHAR2(100);
BEGIN
-- 프로시저를 부를 경우 out되는 값을 받기 위해 변수를 하나 더 전달해야 한다.
my_new_job_proc('JOB1', 'test_job1', 2000, 8000, str);
DBMS_OUTPUT.put_line(str);
my_new_job_proc('CEO', 'test_CEO', 10000, 100000, str);
DBMS_OUTPUT.put_line(str);
END;
-- IN, OUT을 동시에 처리
CREATE OR REPLACE PROCEDURE my_parameter_test_proc
(
-- 반환 불가
p_var1 IN VARCHAR2,
-- 반환 가능 하지만 OUT변수는 프로시저가 끝나기 전까지 값의 할당이 안되고 프로시저가 끝나야만 OUT 가능
p_var2 OUT VARCHAR2,
-- IN, OUT이 둘 다 가능하다.
p_var3 IN OUT VARCHAR2
)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('p_var1: ' || p_var1);
DBMS_OUTPUT.PUT_LINE('p_var2: ' || p_var2); -- 값이 전달이 안된다. (공백)
DBMS_OUTPUT.PUT_LINE('p_var3: ' || p_var3); -- IN의 성질을 가지고 있다.
-- p_var1 := '결과1'; 할당 불가 (프로시저 안에서 새로운 값을 할당 할 수 없다.)
p_var2 := '결과2';
p_var3 := '결과3';
DBMS_OUTPUT.PUT_LINE('-------------------------------');
END;
--RETURN
CREATE OR REPLACE PROCEDURE my_new_job_proc
(p_job_id IN jobs.job_id%TYPE,
p_result OUT VARCHAR2)
IS
v_cnt NUMBER := 0;
v_result VARCHAR(100) := '값이 없어서 insert 처리 되었습니다.';
BEGIN
SELECT COUNT(*)
INTO v_cnt
FROM jobs
WHERE job_id = p_job_id;
IF v_cnt = 0 THEN
DBMS_OUTPUT.PUT_LINE(p_job_id || '는 테이블에 존재하지 않습니다.');
RETURN; -- 프로시저 강제종료
END IF;
SELECT p_job_id || '의 최대 연봉: ' || max_salary || ', ' || '최소연봉: ' || min_salary
INTO v_result -- 조회 결과를 대입
FROM jobs
WHERE job_id = p_job_id;
-- OUT 매개변수에 결과를 할당
p_result := v_result;
END;
DECLARE
str VARCHAR2(100);
BEGIN
my_new_job_proc('CEO', str);
DBMS_OUTPUT.PUT_LINE(str);
END;
-- 예외처리
DECLARE
v_num NUMBER := 0;
BEGIN
v_num := 10 / 0;
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('0으로 나눌 수 없습니다.');
DBMS_OUTPUT.PUT_LINE('SQL ERROR CODE: ' || SQLCODE);
DBMS_OUTPUT.PUT_LINE('ERROR MSG: ' || SQLERRM);
END;
PL/SQL Quiz03
문제1. 프로시저명 guguProc 구구단을 입력받아 해당 단수를 출력하는 procedure을 생성
CREATE OR REPLACE PROCEDURE guguProc (
p_dan IN NUMBER
)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE(p_dan || '단');
FOR i IN 1..9
LOOP
DBMS_OUTPUT.PUT_LINE(p_dan || 'x' || i || ' = ' || p_dan * i);
END LOOP;
END;
EXEC guguProc(7);
문제2. 부서번호, 부서명, 직업 flag(I: insert, U:update, D:delete)을 매개변수로 받아 depts 테이블에 각각 INSERT, UPDATE, DELETE 하는 DEPTS_PROC란 이름의 프로시저를 만든다. 그리고 정상종료라면 commit, 예외라면 롤백 처리하도록 처리한다.
CREATE TABLE depts AS SELECT department_id, department_name FROM departments;
ALTER TABLE depts ADD CONSTRAINTS depts_pk PRIMARY KEY(department_id);
CREATE OR REPLACE PROCEDURE depts_proc (
p_department_id IN depts.department_id%TYPE,
p_department_name IN depts.department_name%TYPE,
p_flag IN VARCHAR2
)
IS
BEGIN
IF p_flag = 'I' THEN
INSERT INTO depts VALUES (p_department_id, p_department_name);
ELSIF p_flag = 'U' THEN
UPDATE depts
SET department_name = p_department_name
WHERE department_id = p_department_id;
ELSIF p_flag = 'D' THEN
DELETE depts
WHERE department_id = p_department_id;
END IF;
COMMIT;
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('예외가 발생했습니다.');
DBMS_OUTPUT.PUT_LINE('ERROR MSG: ' || SQLERRM);
ROLLBACK;
END;
EXEC depts_proc(11, '마케팅부', 'D');
SELECT * FROM depts;
CREATE OR REPLACE PROCEDURE emp_hire_proc (
p_employee_id IN employees.employee_id%TYPE,
p_year OUT NUMBER
)
IS
v_hire_date employees.hire_date%TYPE;
BEGIN
SELECT hire_date
INTO v_hire_date
FROM employees
WHERE employee_id = p_employee_id;
p_year := TRUNC((sysdate - v_hire_date) / 365);
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(p_employee_id || '은(는) 없는 데이터입니다.');
DBMS_OUTPUT.PUT_LINE('ERROR MSG: ' || SQLERRM);
END;
DECLARE
v_year NUMBER;
BEGIN
emp_hire_proc(100, v_year);
DBMS_OUTPUT.PUT_LINE(v_year);
END;
문제4. 프로시저명 - new_emp_proc employees 테이블의 복사 테이블 emps를 생성 employee_id, last_name, email, hire_date, job_id를 입력받아 존재하면 이름, 이메일, 입사일, 직업을 update, 없다면 insert하는 merge문을 작성
CREATE OR REPLACE PROCEDURE new_emp_proc (
p_employee_id IN emps.employee_id%TYPE,
p_last_name IN emps.last_name%TYPE,
p_email IN emps.email%TYPE,
p_hire_date IN emps.hire_date%TYPE,
p_job_id IN emps.job_id%TYPE
)
IS
BEGIN
MERGE INTO emps a
USING (SELECT p_employee_id AS employee_id FROM dual) b
ON (a.employee_id = b.employee_id)
WHEN MATCHED THEN
UPDATE SET
a.last_name = p_last_name,
a.email = p_email,
a.hire_date = p_hire_date,
a.job_id = p_job_id
WHEN NOT MATCHED THEN
INSERT (a.employee_id, a.last_name, a.email, a.hire_date, a.job_id)
VALUES (p_employee_id, p_last_name, p_email, p_hire_date, p_job_id);
END;
EXEC new_emp_proc(100, 'lee', 'abc', sysdate, 'test2');
Trigger
테이블에 부착한 형태로 INSERT, UPDATE, DELETE 작업이 수행될 때 특정 코드가 작동되도록 하는 구문이다.
trigger는 실행할 때 범위를 지정하고 F5버튼으로 부분 실행해야 하며, 그렇지 않으면 하나의 구문으로 인식되어 정상 동작하지 않는다.
CREATE TABLE tbl_test (
id NUMBER(10),
text VARCHAR2(20)
);
CREATE OR REPLACE TRIGGER trg_test
AFTER DELETE OR UPDATE -- 삭제 혹은 수정 이후에 동작
ON tbl_test -- 부착할 테이블 선언
FOR EACH ROW -- 각 행에 적용
BEGIN
DBMS_OUTPUT.PUT_LINE('트리거 동작'); -- 실행되는 코드를 begin ~ end에 넣는다.
END;
INSERT INTO tbl_test VALUES(1, '홍길동');
UPDATE tbl_test SET text = '홍길동2' WHERE id = 1;
DELETE FROM tbl_test WHERE id = 1;
trigger After & before
AFTER trigger - INSERT, UPDATE, DELETE 작업 이후에 동작하는 트리거를 의미한다.
BEFORE trigger - INSERT, UPDATE, DELETE 작업 이전에 동작하는 트리거를 의미한다.
INSTEAD OF trigger - INSERT, UPDATE, DELETE 작업 이전에 발생하는 트리거 이지만 VIEW만 부착할 수 있다.
:OLD = 참조 전 열의 값 (INSERT: 입력 전 자료, UPDATE: 수정 전 자료, DELETE: 삭제할 값)
:NEW = 참조 후 열의 값 (INSERT: 입력 할 자료, UPDATE: 수정 된 자료) :NEW는 DELETE가 없다.
테이블에 UPDATE나 DELETE를 시도하면 수정 또는 삭제된 데이터를 별도의 테이블에 보관해 놓는 형식으로 트리거를 사용할 수 있다.
CREATE TABLE tbl_user (
id VARCHAR(20) PRIMARY KEY,
name VARCHAR2(20),
address VARCHAR2(30)
);
CREATE TABLE tbl_user_backup (
id VARCHAR2(20),
name VARCHAR2(20),
address VARCHAR2(30),
update_date DATE DEFAULT sysdate, -- 변경 시간
m_type VARCHAR2(10), -- 변경 타입
m_user VARCHAR2(20) -- 변경한 사용자
);
AFTER trigger
CREATE OR REPLACE TRIGGER trg_user_backup
AFTER UPDATE OR DELETE
ON tbl_user
FOR EACH ROW
DECLARE -- 사용할 변수를 선언
v_type VARCHAR2(10);
BEGIN
IF UPDATING THEN -- UPDATING은 시스템 자체에서 상태에 대한 내용을 지원하는 빌트인 구문
v_type := '수정';
ELSIF DELETING THEN -- DELETING은 시스템 자체에서 상태에 대한 내용을 지원하는 빌트인 구문
v_type := '삭제';
END IF;
-- 실행 구문 시작 (:OLD는 테이블 DELETE, UPDATE가 적용되기 전 기존데이터, 즉 변경 전 데이터)
INSERT INTO tbl_user_backup
VALUES (:OLD.id, :OLD.name, :OLD.address, sysdate, v_type, USER());
END;
UPDATE tbl_user SET address = '서울' WHERE id = 'test01';
SELECT * FROM tbl_user;
SELECT * FROM tbl_user_backup;
BEFORE trigger
CREATE OR REPLACE TRIGGER trg_user_insert
BEFORE INSERT
ON tbl_user
FOR EACH ROW
BEGIN
:NEW.name := SUBSTR(:NEW.name, 1, 1) || '**';
END;
INSERT INTO tbl_user VALUES('test04', '홍길동', '대구');
SELECT * FROM tbl_user;
-- 주문 히스토리
CREATE TABLE order_history (
history_no NUMBER(5) PRIMARY KEY,
order_no NUMBER (5),
product_no NUMBER(5),
total NUMBER(10),
price NUMBER(10)
);
-- 상품
CREATE TABLE product (
product_no NUMBER(5) PRIMARY KEY,
product_name VARCHAR2(20),
total NUMBER(5),
price NUMBER(5)
);
CREATE SEQUENCE order_history_seq NOCACHE;
CREATE SEQUENCE product_seq NOCACHE;
INSERT INTO product VALUES(product_seq.NEXTVAL, '피자', 100, 10000);
INSERT INTO product VALUES(product_seq.NEXTVAL, '치킨', 100, 15000);
INSERT INTO product VALUES(product_seq.NEXTVAL, '햄버거', 100, 5000);
-- 주문 히스토리에 데이터가 들어오면 실행
CREATE OR REPLACE TRIGGER trg_order_history
AFTER INSERT
ON order_history
FOR EACH ROW
DECLARE
v_total NUMBER;
v_product_no NUMBER;
BEGIN
DBMS_OUTPUT.PUT_LINE('트리거 실행');
SELECT :NEW.total
INTO v_total
FROM dual;
v_product_no := :NEW.product_no;
UPDATE product SET total = total - v_total
WHERE product_no = v_product_no;
END;
INSERT INTO order_history VALUES(order_history_seq.NEXTVAL, 200, 1, 5, 50000);
INSERT INTO order_history VALUES(order_history_seq.NEXTVAL, 200, 2, 1, 15000);
INSERT INTO order_history VALUES(order_history_seq.NEXTVAL, 200, 3, 10, 50000);
SELECT * FROM order_history;
SELECT * FROM product;
댓글