-- 1. 테스트용 함수 생성
----------------------------------------------------------------
CREATE OR REPLACE FUNCTION FNC_TEST RETURN VARCHAR2
IS
    P_RTN VARCHAR2(1000);
BEGIN

    DBMS_OUTPUT.PUT_LINE('호출');

    SELECT SYS_GUID()
    INTO P_RTN
    FROM DUAL;
    
    RETURN P_RTN;
    
    EXCEPTION
        WHEN OTHERS THEN
            RETURN NULL;

END;



-- 2. 나쁜 쿼리 (매번호출)
----------------------------------------------------------------
SELECT  T.ID
,       T.ID
,       T.ID
FROM (SELECT FNC_TEST() AS ID
      FROM DUAL) T;


-- DBMS 출력
호출
호출
호출


-- 스크립트 출력
ID                                  ID                                  ID
--------------------------------    --------------------------------    --------------------------------
CB7F1CCA4EF941A1BABAD9CDBAC5CBEE    5A0FB87B0B354A589D52BCDF1A59A4A3    D6E5F959D6114C179FFF7CD746DB3B3C





-- 3. 착한 쿼리 (한번호출)
----------------------------------------------------------------
SELECT  T.ID
,       T.ID
,       T.ID
FROM (SELECT (SELECT FNC_TEST() FROM DUAL) AS ID
      FROM DUAL) T;


-- DBMS 출력
호출


-- 스크립트 출력
ID                                  ID                                  ID
--------------------------------    --------------------------------    --------------------------------
BB30D177761549039C4B780030A0ECB3    BB30D177761549039C4B780030A0ECB3    BB30D177761549039C4B780030A0ECB3



-- 이렇게 해도 한번만 호출된다....왜? ROWNUM으로 발번한 중간집합을 어떤식으로든 가지고 있어야 하기 때문이다.
-- 즉, 중간집합을 가지도록 할 수 있는 방법을 유도한다면 다른 식으로도 얼마든지 가능할 것이다.
SELECT  T.ID
,       T.ID
,       T.ID
FROM (SELECT ROWNUM, FNC_TEST() AS ID
      FROM DUAL) T;




-- 4. 캐시
----------------------------------------------------------------
CREATE OR REPLACE FUNCTION FNC_TEST(P_USR_ID ESAUSER.USR_ID%TYPE) RETURN VARCHAR2
IS
    P_RTN VARCHAR2(1000);
BEGIN

    DBMS_OUTPUT.PUT_LINE('CALL');
    
    SELECT USR_NM 
    INTO P_RTN
    FROM ESAUSER
    WHERE SYS_ID = 'AP'
    AND USR_ID = P_USR_ID;
    
    RETURN P_RTN;
    
    EXCEPTION
        WHEN OTHERS THEN
            RETURN NULL;
END;




WITH TBL
AS
(   SELECT 'ADMIN'      AS USR_ID FROM DUAL UNION ALL
    SELECT 'AP494777'   AS USR_ID FROM DUAL UNION ALL
    SELECT 'ADMIN'      AS USR_ID FROM DUAL UNION ALL
    SELECT 'AP494777'   AS USR_ID FROM DUAL UNION ALL
    SELECT 'ADMIN'      AS USR_ID FROM DUAL UNION ALL
    SELECT 'AP495713'   AS USR_ID FROM DUAL UNION ALL
    SELECT 'AP494777'   AS USR_ID FROM DUAL
)
SELECT  USR_ID
,       (SELECT FNC_TEST(USR_ID) FROM DUAL) AS USR_NM
FROM TBL;


USR_ID                                             USR_NM                                            
-------------------------------------------------- --------------------------------------------------
ADMIN                                              ADMINISTRATOR                                     
AP494777                                           정모씨                                            
ADMIN                                              ADMINISTRATOR                                     
AP494777                                           정모씨                                            
ADMIN                                              ADMINISTRATOR                                     
AP495713                                           김모씨
AP494777                                           정모씨                                            



CALL
CALL
CALL