📚 Study/Oracle

Oracle :: FUNCTION (함수)

bono-hye 2023. 11. 6. 23:36

■ FUNCTION

- 하나 이상의 PL/SQL 문으로 구성된 서브루틴으로 코드를 다시 사용할 수 있도록 캡슐화 하는데 사용

- 오라클에서는 오라클에 정의된 기본 제공 함수를 사용하거나 직접 스토어드 함수를 만들 수 있음(→ 사용자 정의 함수)

- 사용자 정의 함수는 시스템 함수처럼 쿼리에서 호출하거나 저장 프로시저처럼 EXCUTE 문을 통해 실행 가능

 

※ 사용자 정의 함수(스토어드 함수)는 IN 파라미터(입력 매개변수)만 사용할 수 있으며

    반드시 반환될 값의 데이터 타입을 RETURN 문에 선언해야 하고, FUNCTION은 반드시 단일 값만 반환!!

 

입력 매개변수 : 이사와서 이웃집에 떡 줌(주고 끝)

출력 매개변수 : 엄마한테 빈 김치통 건네면 엄마가 빈 김치통에 김치 넣어서 돌려줌
입출력 매개변수 : 김치통에 고구마 넣어서 엄마아빠 주고 김치통 비면 김치 넣어옴

 

■ 형식 및 구조

/*
CREATE [OR REPLACE] FUNCTION 함수명
[( 매개변수명1 자료형
 , 매개변수명2 자료형
)]
RETURN 데이터타입
IS
    -- 주요 변수 선언
BEGIN
    -- 실행문;
    ...
    RETURN (값);
    
    [EXCEPTION]
        -- 예외 처리 구문;
END;
*/

 

■ 함수 생성 예시

--○ TBL_INSA 테이블 전용 성별 확인 함수 정의(생성)
--   -------------------
--   매개변수 구조(형태) → '771212-1022432' → 'YYMMDD-NNNNNNN'
-- 함수명 : FN_GENDER( )
--                   ↑ 주민등록번호 → '771212-1022432'


CREATE OR REPLACE FUNCTION FN_GENDER(V_SSN VARCHAR2)    -- 매개변수   : 자릿수(길이) 지정 안함
RETURN VARCHAR2                                         -- 반환자료형 : 자릿수(길이) 지정 안함
IS
    -- 선언부 → 주요 변수 선언(및 초기화)
    V_RESULT    VARCHAR2(20);
BEGIN
    -- 실행부 → 연산 및 처리(그리고 결과값 반환)
    IF ( SUBSTR(V_SSN, 8, 1) IN ('1', '3') )
        THEN V_RESULT := '남자';
    ELSIF ( SUBSTR(V_SSN, 8, 1) IN ('2', '4') )
        THEN V_RESULT := '여자';
    ELSE 
        V_RESULT := '성별확인불가';
    END IF;
    
    -- 결과값 반환   CHECK~!! 꼭 써줘야 한다!!
    RETURN V_RESULT;
END;
--==>> Function FN_GENDER이(가) 컴파일되었습니다.

 

■ 실습1

--○ 임의의 정수 두 개를 매개변수(입력 파라미터)로 넘겨받아 → (A, B)
--   A 의 B 승의 값을 반환하는 사용자 정의 함수를 작성한다.
--   단, 기존의 오라클 내장 함수를 이용하지 않고, 반복문을 활용하여 작성한다.
--   함수명 : FN_POW()
/*
사용 예)
SELECT FN_POW(10, 3)
FROM DUAL;
--==>> 1000
*/

-- 제가 해보았습니다~!    반환값 초기화 값 확인해서 다시 생각해보기
CREATE OR REPLACE FUNCTION FN_POW(A NUMBER, B NUMBER)
RETURN NUMBER
IS
    V_RESULT    NUMBER := 1;
    N           NUMBER;             -- 곱해주는 횟수
BEGIN
    N := 1;
    LOOP
        V_RESULT := V_RESULT * A;
        N := N+1;    
    EXIT WHEN N > B ;
    END LOOP;   
    RETURN V_RESULT;
END;


-- 같이 했씁니다.
CREATE OR REPLACE FUNCTION FN_POW(A NUMBER, B NUMBER)
RETURN NUMBER
IS
    V_RESULT    NUMBER := 1;    -- 반환 결과값 변수 → CHECK~!  1로 초기화
    V_NUM       NUMBER;
BEGIN
    FOR V_NUM IN 1.. B LOOP
        V_RESULT := V_RESULT * A;       -- V_RESULT *= A; (자바에서)
    END LOOP;
    
    --최종 결과값 확인
     RETURN V_RESULT;
END;

 

■ 실습2

--○ TBL_INSA 테이블의 급여 계산 전용 함수를 정의한다.
--   급여는 『(기본금*12)+수당』 기반으로 연산을 수행한다.
--   함수명 : FN_PAY(기본급, 수당)

-- 제가 해보았구용
CREATE OR REPLACE FUNCTION FN_PAY(V_BASIC_PAY NUMBER, V_SUDANG NUMBER)
RETURN NUMBER
IS
    V_RESULT    NUMBER := 1;
BEGIN
    V_RESULT := V_BASIC_PAY *12 + V_SUDANG;
    
    RETURN V_RESULT;
END;

-- 같이 해보겠습니당~!  이 문제에서는 NULL 이 없어서 신경쓰지 못했지만 NULL 처리도 같이 해주자 TBL_EMP 테이블에는 NULL 값이 있는 데이터들도 있다!
CREATE OR REPLACE FUNCTION FN_PAY(VBASICPAY NUMBER, VSUDANG NUMBER)
RETURN NUMBER
IS
    -- 주요 변수 선어
    VRESULT NUMBER;
BEGIN
    -- 연산 및 처리
    VRESULT := (NVL(VBASICPAY, 0) * 12) + NVL(VSUDANG, 0);
    -- 최종 결과값 반환
    RETURN VRESULT;
END;

 

■ 실습3

--○ TBL_INSA 테이블에서
--   입사일을 기준으로 현재까지의 근무년수를 반환하는 함수를 정의한다.
--   단, 근무년수는 소수점 이하 한자리까지 계산한다.
--   함수명 : FN_WORKYEAR(입사일)

-- 나 혼자
CREATE OR REPLACE FUNCTION FN_WORKYEAR(V_IBSADATE DATE)
RETURN NUMBER
IS
    V_RESULT    NUMBER:=0;
BEGIN
    V_RESULT := TRUNC(MONTHS_BETWEEN(SYSDATE, V_IBSADATE)/12, 1);
    
    RETURN V_RESULT;
END;

-- 몇년 몇개월로 뽑았음
CREATE OR REPLACE FUNCTION FN_WORKYEARMONTH(V_IBSADATE DATE)
RETURN VARCHAR2
IS
    V_RESULT     VARCHAR(80);
    V_RESULT1    NUMBER:=0;
    V_RESULT2    NUMBER:=0;
BEGIN
    V_RESULT1 := TRUNC(MONTHS_BETWEEN(SYSDATE, V_IBSADATE)/12, 0);
    V_RESULT2 := TRUNC(MOD(MONTHS_BETWEEN(SYSDATE, V_IBSADATE), 12), 0);
    
    IF 
        V_RESULT2 = 0
            THEN V_RESULT := V_RESULT1 || '년 ';
    ELSE
        V_RESULT := V_RESULT1 || '년 ' || V_RESULT2 ||'개월';
    END IF;    
    RETURN V_RESULT;
END;



-- 같이 
-- 1
SELECT MONTHS_BETWEEN(SYSDATE, TO_DATE('1998-10-11', 'YYYY-MM-DD')) / 12 "RESULT"
FROM DUAL;
--==>> 25.06313778748506571087216248506571087217

-- 2
SELECT TRUNC(MONTHS_BETWEEN(SYSDATE, TO_DATE('1998-10-11', 'YYYY-MM-DD'))/12) || '년' ||
       TRUNC(MOD(MONTHS_BETWEEN(SYSDATE, TO_DATE('1998-10-11', 'YYYY-MM-DD')), 12)) || '개월'
FROM DUAL;
--==>> 25년0개월


CREATE OR REPLACE FUNCTION FN_YEAR(VIBSADATE DATE)
RETURN NUMBER
IS
    VRESULT NUMBER;
BEGIN
    VRESULT := TRUNC(MONTHS_BETWEEN(SYSDATE, VIBSADATE)/12, 1);
    
    RETURN VRESULT;
END;


-- 결과 확인
SELECT NUM, NAME, IBSADATE, FN_WORKYEAR(IBSADATE) "근무기간"
FROM TBL_INSA;

SELECT NUM, NAME, IBSADATE, FN_WORKYEARMONTH(IBSADATE) "입사년개월수"
FROM TBL_INSA;