[mysql] 프로시저와 함수

프로시저와 함수 생성을 위한 권한 설정

// 권한 설정되어 있지 않은 경우 에러메시지
ERROR 1418: This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)

// 권한 설정여부 체크하는 쿼리
**SHOW GLOBAL VARIABLES LIKE 'LOG_BIN_TRUST_FUNCTION_CREATORS';
//** LOG_BIN_TRUST_FUNCTION_CREATORS 값이 OFF이면 생성 불가
// ON 값으로 변경
**SET GLOBAL LOG_BIN_TRUST_FUNCTION_CREATORS = 1;**
  • MySQL에서 프로시저(Procedure)를 사용해 주면 여러 쿼리를 프로시저 하나로 실행시킬 수 있다
  • 함수는 쿼리를 수행한 후 값을 가져오는 것이 중점이지만 프로시저는 여러 쿼리를 한번에 수행하는 것이 중점이다
  • 속도는 프로시저가 더 빠르기에 프로시저 같은 경우 실행, 처리를 할 때 주로 사용되고, 함수는 간단한 계산이나 수치 결과를 나타낼 때 주로 사용한다.

프로시저

  • 프로시저를 호출하면 MySQL은 DataBase카탈로그에서 프로시저 이름을 찾아 SQL문을 컴파일하고 메모리 공간(Cache)에 저장한 뒤 프로시저를 실행시킨다.</aside>
  • <aside> 💡 DB카탈로그 -> SQL컴파일 -> 메모리저장 -> 실행
  • 장점
    1. 하나의 요청으로 여러 SQL문을 실행 가능
    2. 네트워크 소요 시간을 줄일 수 있음(여러개의 쿼리를 처리하는 시점에서 네트워크 부하 줄임)
    3. 보수성이 뛰어나다.
    4. 개발 업무를 구분하여 개발할 수 있다. (DB관련 처리를 API처럼 만들어 제공)
    5. If, case, loop 같은 제어,반복문을 사용해 보다 향상된 SQL코드를 작성할 수 있고 프로시저 내에서 다른 프로시저를 호출할 수도 있다.
  • 단점
    • 프로시저는 처리성능과 재사용면에서 좋지 않다.

예시1 (프로시저 정의)

DELIMITER $$ -- 구분자
CREATE PROCEDURE `PROC_TEST` ( -- 프로시저명
    -- 파라미터 선언
    PARAM_NAME VARCHAR(20) 
    , PARAM_AGE INTEGER
)
BEGIN
    DECLARE PARAM_NUM INTEGER; -- 변수 선언
    
    -- SELECT 사용 시에는 조회한 컬럼을 반드시 INTO로 변수 안에 넣어줘야 에러가 나지 않는다
    SELECT COUNT(*) + 1 
      	INTO PARAM_NUM -- 변수에 값 할당
    FROM TB1;
    
    -- INSERT 문 수행
    INSERT 
        INTO TB1(NUM, NAME, AGE) 
    VALUES
        (PARAM_NUM, PARAM_NAME, PARAM_AGE);
END $$
DELIMITER ;

CALL PROC_TEST('테스트',30); -- 프로시저 실행
SELECT NAME, AGE, NUM FROM TB1; -- 프로시저로 삽입된 내용 확인

IN,OUT,INOUT

  • IN
  • 프로시저에 값을 전달하며, 프로시저 내부에서 값을 수정할 수는 있지만 프로시저가 반환되고 나서 호출자가 수정은 불가능하다. 즉, 원본 값은 프로시저가 끝난 후에도 유지되며, 프로시저는 IN 파라미터의 복사본을 사용한다
  • OUT
  • 프로시저의 값을 호출자에게 다시 Return한다. 초기값은 프로시저 내에서 NULL이며 프로시저가 반환될 때 새로운 값이 호출자에게 Return되고 프로그램이 시작될 때, OUT 파라미터의 초기값에 접근할 수 없다.
  • INOUT
  • 호출자에 의해 하나의 변수가 초기화되고 프로시저에 의해 수정된다. 간단하게 IN+OUT이라고 생각하면 될 것 같다. 프로시저가 Return될 때 프로시저가 변경한 사항은 호출자에게 Return된다.

예시 2( IN,OUT,INOUT 사용)

DELIMITER $$
CREATE PROCEDURE 'TEST_PROC2'(
    IN loopCount1 INT,     -- input : 10
    IN loopCount2 INT,     -- input : 20
    OUT rst1 INT,
    OUT rst2 INT,
    INOUT rst3 INT
)
BEGIN
    DECLARE NUM1 INTEGER DEFAULT 0;    -- DEFAULT : 초기값 설정
    DECLARE NUM2 INTEGER DEFAULT 0;
    DECLARE NUM3 INTEGER DEFAULT 0;
    
    WHILE NUM1<loopCount1 DO           -- NUM1은 0~9까지 10번반복
        WHILE NUM2<loopCount2 DO       -- NUM2는 0~19까지 20번반복
            SET NUM3 = NUM3 + 1;
            SET NUM2 = NUM2 + 1;
        END WHILE;                     -- NUM2가 19가 되면 나옴
        
        SET NUM1 = NUM1 + 1;
        SET NUM2 = 0;
    END WHILE;
    
    SET rst1 = NUM1; -- 첫번째 WHILE에서 10
    SET rst2 = NUM3; -- WHILE 2개가 마칠 때까지 더해져서 200
    SET rst3 = rst1 + rst2 + rst3; -- 240 = 10+200+(호출 시 @NUM3에 할당한 값) 30  
END $$
DELIMITER ;

이번에는 파라미터에 IN, OUT을 사용하고 프로시저 내부에서 반복문도 사용해보았다. IN, OUT, INOUT 이외 문법에 대해서는 아래에 추가적으로 설명할 예정이다.

예시 2 (호출)

-- 변수 초기화
DECLARE @NUM1 = 0;
DECLARE @NUM2 = 0;
DECLARE @NUM3 = 0;

-- NUM3에 값 30 할당(@는 전역변수, 프로시저가 끝나도 계속 유지되는 값)
SET @NUM3 = 30;
CALL TEST_PROC2(10, 20, @NUM1, @NUM2, @NUM3);

SELECT @NUM1, @NUM2, @NUM3; -- RESULT => @NUM1 : 10, @NUM2 : 200, @NUM3 : 240

추가 문법 및 용어 정리

프로시저 목록 확인

SHOW PROCEDURE STATUS;

프로시저 내용 확인

SHOW CREATE PROCEDURE 프로시저이름;

프로시저 삭제

DROP PROCEDURE 프로시저이름;

ex ) DROP PROCEDURE IF EXISTS procedure_name; (이미 프로시저가 정의 되어 있다면 삭제)

조건문(IF)예시

IF total >= 95 AND total <= 100 THENSET grade = 'A+';
ELSE
    IF total >= 90 THENSET grade = 'A';
    END IF;
END IF;

조건문(CASE)예시

CASE NUM
    WHEN 'Apple' THENSET 'result_Str' = 'apple_cookie';
    WHEN 'Banana' THENSET 'result_Str' = 'banana_cookie';
    ELSESET 'result_Str' = 'orange_cookie';
END CASE;

함수

CREATE FUNCTION 'GET_NAME' ( -- 함수명
		NAME VARCHAR(20) -- 파라미터
) RETURNS VARCHAR(20) -- 반환할 데이터타입
BEGIN
	-- 변수 선언
	DECLARE NAME_TITLE VARCHAR(20); 
	DECLARE RETURN_VALUE VARCHAR(20);

	-- 수행할 쿼리
	SELECT CONCAT(NAME, ' IS ') INTO NAME_TITLE; -- 조회한 컬럼은 INTO로 변수에 넣어야 함
	SET RETURN_VALUE = NAME_TITLE; -- 변수에 값을 넣을 때 SET을 사용한다

	RETURN RETURN_VALUE; -- 반환할 값
END

// 함수 호출 시
SELECT GET_NAME('철수');

레퍼런스

https://wakestand.tistory.com/518

https://wakestand.tistory.com/503

https://wakestand.tistory.com/502

https://spiderwebcoding.tistory.com/7