몇 단계 전에 이미 PostgreSQL에서 프로시저와 함수에 대해 얘기했었지. 이제 좀 더 깊게 파보자.
함수랑 프로시저는 따로따로 쓸 수도 있지만, 보통은 둘의 상호작용이 시스템 전체의 성공을 좌우해. 제일 편한 점은, 함수 안에서 다른 함수를 호출할 수 있고, 데이터를 넘기거나 결과값도 받을 수 있다는 거야.
함수 vs 프로시저: 뭐가 다를까?
PostgreSQL에서 함수와 프로시저가 어떻게 다른지 다시 한 번 정리해보자:
함수 (
FUNCTION):- 값을 반환해.
SELECT에서 쓸 수 있어.- 주로 계산이나 데이터 변환에 자주 써.
프로시저 (
PROCEDURE):- 직접적으로 값을 반환하지 않아.
- 데이터 삽입, 수정, 삭제 같은 작업에 써.
CALL명령어로 호출해.
함수 간 데이터 전달
실전으로 들어가서, 함수와 프로시저 사이에서 데이터를 전달하는 기본 예제를 보자. 사실 함수 간 데이터 전달은 파라미터랑 반환값을 통해 이루어져.
아래는 함수 안에서 다른 함수를 호출하는 예시야:
CREATE OR REPLACE FUNCTION get_student_name(student_id INT)
RETURNS TEXT AS $$
DECLARE
student_name TEXT;
BEGIN
-- student_id로 학생 이름 가져오기
SELECT name INTO student_name FROM students WHERE id = student_id;
-- 이름 반환
RETURN student_name;
END;
$$ LANGUAGE plpgsql;
이 함수는 다른 함수에서 이렇게 호출할 수 있어:
CREATE OR REPLACE FUNCTION welcome_student(student_id INT)
RETURNS TEXT AS $$
DECLARE
message TEXT;
BEGIN
-- 다른 함수로 학생 이름 받아오기
message := 'Welcome, ' || get_student_name(student_id) || '!';
-- 환영 메시지 반환
RETURN message;
END;
$$ LANGUAGE plpgsql;
get_student_name함수는student_id로 학생 이름을 반환해.- 다른 함수인
welcome_student에서는 이 이름을 받아서 환영 메시지를 만들어.
참고: SELECT INTO로 데이터를 뽑으면 PL/pgSQL 변수에 결과가 저장돼.
함수에서 프로시저 호출 예시
이번엔 함수에서 프로시저를 호출하는 방법을 보자. 예를 들어, 학생이 시스템에 로그인한 시간을 기록하는 프로시저가 있다고 해보자:
CREATE OR REPLACE PROCEDURE log_student_entry(student_id INT)
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO log_entries(student_id, entry_time)
VALUES (student_id, NOW());
END;
$$;
이제 이 프로시저를 함수에서 호출해서, 로그인 기록을 남기고 메시지를 반환해보자:
CREATE OR REPLACE FUNCTION student_login(student_id INT)
RETURNS TEXT AS $$
BEGIN
-- 로그 기록용 프로시저 호출
CALL log_student_entry(student_id);
-- 메시지 반환
RETURN '학생 로그인 기록 완료.';
END;
$$ LANGUAGE plpgsql;
실전 상호작용 예제
예제 1: 주문 총액 계산과 주문 로그 기록
온라인 주문 시스템을 만든다고 해보자. 주문의 총액을 계산하는 함수가 있어:
CREATE OR REPLACE FUNCTION calculate_order_total(order_id INT)
RETURNS NUMERIC AS $$
DECLARE
total NUMERIC;
BEGIN
-- 주문 항목 모두 합산
SELECT SUM(price * quantity) INTO total
FROM order_items
WHERE order_id = order_id;
RETURN total;
END;
$$ LANGUAGE plpgsql;
주문 총액을 저장하는 프로시저는 이렇게 만들어:
CREATE OR REPLACE PROCEDURE log_order_total(order_id INT, total NUMERIC)
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO order_totals(order_id, total)
VALUES (order_id, total);
END;
$$;
이제 둘을 연결해보자:
CREATE OR REPLACE FUNCTION process_order(order_id INT)
RETURNS TEXT AS $$
DECLARE
total NUMERIC;
BEGIN
-- 총액 계산 함수 호출
total := calculate_order_total(order_id);
-- 프로시저로 총액 기록
CALL log_order_total(order_id, total);
RETURN '주문 처리 완료.';
END;
$$ LANGUAGE plpgsql;
예제 2: 학생 최고 점수 가져오기와 프로필 업데이트
최고 점수를 가져오는 함수:
CREATE OR REPLACE FUNCTION get_highest_rating(student_id INT)
RETURNS INT AS $$
DECLARE
max_rating INT;
BEGIN
-- 학생의 최고 점수 찾기
SELECT MAX(rating) INTO max_rating
FROM ratings
WHERE student_id = student_id;
RETURN max_rating;
END;
$$ LANGUAGE plpgsql;
학생 프로필을 업데이트하는 프로시저:
CREATE OR REPLACE PROCEDURE update_student_profile(student_id INT, max_rating INT)
LANGUAGE plpgsql
AS $$
BEGIN
UPDATE students
SET highest_rating = max_rating
WHERE id = student_id;
END;
$$;
이 둘을 호출하는 함수:
CREATE OR REPLACE FUNCTION refresh_student_profile(student_id INT)
RETURNS TEXT AS $$
DECLARE
max_rating INT;
BEGIN
-- 최고 점수 받아오기
max_rating := get_highest_rating(student_id);
-- 학생 프로필 업데이트
CALL update_student_profile(student_id, max_rating);
RETURN '프로필 업데이트 완료.';
END;
$$ LANGUAGE plpgsql;
상호작용에서 흔한 실수
가장 흔한 실수 중 하나는 함수와 프로시저 사이의 데이터 타입이 안 맞는 거야. 예를 들어, 프로시저가 NUMERIC 타입을 기대하는데 INTEGER를 넘기면 PostgreSQL이 타입 불일치 에러를 내. 항상 데이터 타입이 맞는지 확인하자.
또 다른 실수는 함수 A가 함수 B를 호출하고, B가 다시 A를 호출하는 식의 순환 호출이야. 이러면 무한 루프가 돌면서 시스템이 뻗어버려.
실전에서 왜 중요할까?
왜 이런 상호작용이 필요할까? 실제로 함수와 프로시저는 복잡한 시스템의 "블록"처럼 동작해. 코드를 독립적인 부분으로 나눌 수 있어서 디버깅, 재사용, 테스트가 훨씬 쉬워져. 예를 들어:
- 면접에서 복잡한 작업을 위해 프로시저를 호출하는 함수를 짜보라고 할 수도 있어. 이런 상호작용을 잘 보여주면 점수 따기 좋아.
- 실제 앱(쇼핑몰, 로그 시스템, CRM 등) 개발할 때 함수와 프로시저를 잘 나눠서 쓰면 코드가 훨씬 깔끔해져.
함수와 프로시저의 상호작용을 더 공부하고 싶으면 PL/pgSQL 공식 문서를 참고해봐.
GO TO FULL VERSION