[MySQL] 09. 뷰, 스토어드 프로시저, 함수, 트리거
뷰(View), 스토어드 프로시저(Stored Procedure), 사용자 정의 함수(Function), 트리거(Trigger)를 정리합니다.
뷰 (View)
뷰는 하나 이상의 테이블에서 데이터를 조회하는 가상 테이블입니다.
실제 데이터를 저장하지 않고, 쿼리 결과를 테이블처럼 사용할 수 있습니다.
뷰 생성
-- 기본 뷰 생성
CREATE VIEW v_employee_dept AS
SELECT e.id, e.name, d.name AS dept_name, e.salary
FROM employees e
INNER JOIN departments d ON e.dept_id = d.id;
-- 뷰 사용 (테이블처럼 조회)
SELECT * FROM v_employee_dept WHERE dept_name = '개발팀';
뷰 수정 및 삭제
-- 뷰 수정 (없으면 생성)
CREATE OR REPLACE VIEW v_employee_dept AS
SELECT e.id, e.name, d.name AS dept_name, e.salary, e.hire_date
FROM employees e
INNER JOIN departments d ON e.dept_id = d.id;
-- 뷰 삭제
DROP VIEW v_employee_dept;
DROP VIEW IF EXISTS v_employee_dept;
-- 뷰 목록 확인
SHOW FULL TABLES WHERE Table_type = 'VIEW';
뷰 활용 사례
| 용도 | 설명 |
|---|---|
| 보안 | 민감한 컬럼(급여, 비밀번호)을 제외한 뷰 제공 |
| 편의성 | 복잡한 JOIN 쿼리를 뷰로 단순화 |
| 일관성 | 자주 사용하는 쿼리를 뷰로 통일 |
-- 보안 뷰: 급여 정보 제외
CREATE VIEW v_employee_public AS
SELECT id, name, dept_id, hire_date FROM employees;
스토어드 프로시저 (Stored Procedure)
미리 컴파일된 SQL 문의 집합으로, 서버에 저장되어 호출하여 실행합니다.
기본 프로시저
-- 구분자 변경 (프로시저 내부에서 ; 사용을 위해)
DELIMITER //
CREATE PROCEDURE sp_get_employees_by_dept(IN p_dept_id INT)
BEGIN
SELECT id, name, salary
FROM employees
WHERE dept_id = p_dept_id
ORDER BY salary DESC;
END //
DELIMITER ;
-- 프로시저 호출
CALL sp_get_employees_by_dept(1);
파라미터 종류
| 종류 | 설명 | 예시 |
|---|---|---|
| IN | 입력 파라미터 (기본값) | IN p_id INT |
| OUT | 출력 파라미터 | OUT p_count INT |
| INOUT | 입출력 파라미터 | INOUT p_value INT |
OUT 파라미터 예시
DELIMITER //
CREATE PROCEDURE sp_get_dept_stats(
IN p_dept_id INT,
OUT p_count INT,
OUT p_avg_salary DECIMAL(10,2)
)
BEGIN
SELECT COUNT(*), AVG(salary)
INTO p_count, p_avg_salary
FROM employees
WHERE dept_id = p_dept_id;
END //
DELIMITER ;
-- 호출 및 결과 확인
CALL sp_get_dept_stats(1, @cnt, @avg);
SELECT @cnt AS 인원수, @avg AS 평균급여;
제어문 사용
DELIMITER //
CREATE PROCEDURE sp_update_salary(
IN p_emp_id INT,
IN p_raise_pct DECIMAL(5,2)
)
BEGIN
DECLARE v_current_salary DECIMAL(10,2);
DECLARE v_new_salary DECIMAL(10,2);
-- 현재 급여 조회
SELECT salary INTO v_current_salary
FROM employees WHERE id = p_emp_id;
-- 조건 분기
IF v_current_salary IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '직원을 찾을 수 없습니다';
ELSEIF p_raise_pct > 50 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '인상률은 50%를 초과할 수 없습니다';
ELSE
SET v_new_salary = v_current_salary * (1 + p_raise_pct / 100);
UPDATE employees SET salary = v_new_salary WHERE id = p_emp_id;
SELECT CONCAT(p_emp_id, '번 직원 급여 변경: ', v_current_salary, ' → ', v_new_salary) AS 결과;
END IF;
END //
DELIMITER ;
반복문
DELIMITER //
CREATE PROCEDURE sp_insert_test_data(IN p_count INT)
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i <= p_count DO
INSERT INTO test_table (name, value)
VALUES (CONCAT('item_', i), FLOOR(RAND() * 1000));
SET i = i + 1;
END WHILE;
END //
DELIMITER ;
CALL sp_insert_test_data(100);
프로시저 관리
-- 프로시저 목록
SHOW PROCEDURE STATUS WHERE Db = 'mydb';
-- 프로시저 내용 확인
SHOW CREATE PROCEDURE sp_get_employees_by_dept;
-- 프로시저 삭제
DROP PROCEDURE IF EXISTS sp_get_employees_by_dept;
사용자 정의 함수 (Function)
프로시저와 유사하지만, 반드시 값을 반환하며 SELECT 문 안에서 사용할 수 있습니다.
DELIMITER //
CREATE FUNCTION fn_salary_grade(p_salary DECIMAL(10,2))
RETURNS VARCHAR(10)
DETERMINISTIC
BEGIN
DECLARE v_grade VARCHAR(10);
IF p_salary >= 7000000 THEN SET v_grade = 'S';
ELSEIF p_salary >= 5000000 THEN SET v_grade = 'A';
ELSEIF p_salary >= 3000000 THEN SET v_grade = 'B';
ELSE SET v_grade = 'C';
END IF;
RETURN v_grade;
END //
DELIMITER ;
-- 함수 사용
SELECT name, salary, fn_salary_grade(salary) AS 등급 FROM employees;
프로시저 vs 함수
| 항목 | 프로시저 | 함수 |
|---|---|---|
| 반환값 | 없거나 OUT 파라미터 | 반드시 RETURN |
| 호출 방법 | CALL 프로시저명() |
SELECT 함수명() |
| SQL 내 사용 | 불가 | SELECT, WHERE 등에서 사용 가능 |
| 트랜잭션 | 사용 가능 | 제한적 |
트리거 (Trigger)
특정 테이블에 INSERT, UPDATE, DELETE가 발생할 때 자동으로 실행되는 프로시저입니다.
트리거 생성
-- 급여 변경 이력 테이블
CREATE TABLE salary_log (
id INT PRIMARY KEY AUTO_INCREMENT,
emp_id INT NOT NULL,
old_salary DECIMAL(10,2),
new_salary DECIMAL(10,2),
changed_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 급여 변경 시 자동 로그 기록
DELIMITER //
CREATE TRIGGER trg_salary_change
AFTER UPDATE ON employees
FOR EACH ROW
BEGIN
IF OLD.salary != NEW.salary THEN
INSERT INTO salary_log (emp_id, old_salary, new_salary)
VALUES (OLD.id, OLD.salary, NEW.salary);
END IF;
END //
DELIMITER ;
트리거 타이밍
| 타이밍 | 이벤트 | 설명 |
|---|---|---|
| BEFORE INSERT | INSERT 전 | 데이터 검증, 기본값 설정 |
| AFTER INSERT | INSERT 후 | 로그 기록, 연관 테이블 업데이트 |
| BEFORE UPDATE | UPDATE 전 | 변경 전 검증 |
| AFTER UPDATE | UPDATE 후 | 변경 이력 기록 |
| BEFORE DELETE | DELETE 전 | 삭제 전 검증 |
| AFTER DELETE | DELETE 후 | 삭제 이력 기록 |
OLD / NEW 키워드
| 이벤트 | OLD | NEW |
|---|---|---|
| INSERT | 사용 불가 | 새로 삽입되는 값 |
| UPDATE | 변경 전 값 | 변경 후 값 |
| DELETE | 삭제되는 값 | 사용 불가 |
트리거 관리
-- 트리거 목록
SHOW TRIGGERS;
-- 트리거 삭제
DROP TRIGGER IF EXISTS trg_salary_change;
- [MySQL] 13. 자주 발생하는 Troubleshooting
- [MySQL] 12. 성능 튜닝 (Performance Tuning)
- [MySQL] 11. 백업과 복구 (Backup & Restore)
- [MySQL] 10. 사용자 관리와 권한 (User & Privilege)
- [MySQL] 09. 뷰, 스토어드 프로시저, 함수, 트리거
- [MySQL] 08. 트랜잭션과 락 (Transaction & Lock)
- [MySQL] 07. 인덱스 (Index)
- [MySQL] 06. 내장 함수 정리
- [MySQL] 05. 서브쿼리와 고급 SELECT
- [MySQL] 04. JOIN (테이블 결합)
- [MySQL] 03. CRUD 기본 (INSERT, SELECT, UPDATE, DELETE)
- [MySQL] 02. 데이터베이스와 테이블 관리
- [MySQL] 01. MySQL/MariaDB 소개 및 설치