[재수정] 프로시져 dynamic sql의 cursor에서 조건값에 따른 where절 추가시 파라미터 변경 방법 0 4 2,197

by sun [PL/SQL] [2017.03.12 09:20:56]


기존 질문에서 제가 이해하거나 해결된 부분은 수정했습니다.

아래 질문으로 다시 하겠습니다.

각 조건절마다 USING 파라미터절을 달리 해야하는 방법을  찾고 잇습니다..

 

declare

TYPE CUR_TYPE IS REF CURSOR;
        C_TYPE           CUR_TYPE;

cursor cur_master is

v_SQL :=        'select cust_no ' ;

v_SQL : =        'from cust_sales

v_SQL :=         'where office_cd  = '1000'  ;

 

cursor cur_detail is

v_det :=        'select cust_gb ' ;

v_det=        'from cust ;

v_det         'where office_cd  = '1000'  ;

 

--CUR_M 커서 안에서 CUR_D 커서가 돌아가는 구조임

FOR CUR_M_FOR IN  cur_master
            LOOP

                   FOR CUR_D_FOR  IN  cur_detail

                       -- cust_gb값에 따라 where절을 달리함.

                          IF cust_gb = '10' THEN

                               V_WHERE := V_WHERE  ||  ' and  exists (select 1 from cust_aa where aa = : 1 and bb = :2 )'  

                         ELSIF cust_gb = '20 THEN

                              V_WHERE := V_WHERE  || ' and  exists (select 1 from cust_bb where aaa = :1 and  bbb = : 3 and ccc = :4 AND ddd = :5) -두번째조건

                         ELSIF cust_gb = '30' THEN

                             V_WHERE := V_WHERE  || ' and  exists (select 1 from cust_bbcc where  aabb = :1 and  abbb = : 6 ) -두번째조건

                          ELSIF cust_gb = '40' THEN

                                    ....=> where절이 늘어날 수 있음.

                         END IF;                 

                 END LOOP;

                         -- 하나의 CUR_M 커서가 모두 끝나면 CUR_D에서 만들었던 WHERE문을 모두 합쳐서 REF CURSOR를 실행 함.

                          V_STR := V_SQL|| V_WHERE ;

                          OPEN C_TYPE FOR V_STR USING aa,bb,cc,dd  ; => where절이 늘어날 수 있기 때문에 using 뒤에 몇개의 파라미터를 어떻게 써야할지.. 모르겠습니다.
                          LOOP
                                      FETCH C_TYPE INTO V_CUST_NO;
                                      EXIT WHEN C_TYPE%NOTFOUND;


                                      DBMS_OUTPUT.PUT_LINE(V_CUST_NO);
                          END LOOP;

 END LOOP;

-- 각 V_WHERE 조건마다 USIING 파라미터를 따로 둬서 이것도 나중에 합치는 방법이 있을 까요?

 

제가 구현해야할 프로시져가 위의 기능을 사용해야 딱 맞는거 같긴한데.. 이런식의 다이나믹 SQL을 사용하다보니 원하던 결과가 안나오고

 위의 문제로 인해 제가 잘못알고 작업을 하고 있는거 같아서.. 부탁을 좀 드리려 글을 올렸습니다.

긴문장 이해가 안되실지도 모르시겠지만.. 작업하면서 이 궁금증이 안풀리니깐 시간만 흘러가고 해서 얼른 문제를 해결해야겠다 싶어

도움을 요청합니다. 답변 좀 부탁드리겠습니다.. 감사합니다.                      

by jkson [2017.03.12 19:31:08]

using 절에 따라오는 파라메터는 쿼리에 있는 바인드변수의 순서대로 매칭되기 때문에


조건절이 유동적으로 변하는 경우 유동적으로 변경된 쿼리에 따라

using 문을 분기시켜서 각각 다르게 지정해야합니다.

보통 개발자들이 이게 귀찮아서 using문을 쓰지 않고 쿼리 자체에다가


v_where := v_where || 'and exists (select 1 from ccurst_aa where aa = '''|| v_val1 ||''' and bb = '''|| v_val2 ||''')';

이렇게 사용하기도합니다만.. 이렇게 만들어줄 경우 실행할 때마다 하드파싱이 일어나게

되어 쿼리문 성능에 영향을 줄 수 있습니다.

해당 프로시저가 매우 가끔 수행되는 경우라면 이런 방식으로 만드셔도 크게 무리는 없습니다.

다만 자주 수행되는 경우라면 바인드변수를 사용하셔야 하드파싱을 피하실 수 있을 것이구요.

저도 지식이 많지 않지만 제가 이런 프로시저를 만들어야 한다면

아래 방식으로 만들 것 같습니다.

V_CON10 := 'N';  --V_CON10 생성여부
V_CON20 := 'N';
V_CON30 := 'N';

FOR CUR_D_FOR  IN  CUR_DETAIL

  IF CUST_GB = '10' THEN 
    V_CON10 := 'Y'; --V_CON10 생성여부 = 'Y'
  ELSIF CUST_GB = '20' THEN 
    V_CON20 := 'Y';
  ELSIF CUST_GB = '30' THEN 
    V_CON30 := 'Y';
  --생략
  END IF;                 

END LOOP;

IF V_CON10 = 'Y' THEN
  V_WHERE := V_WHERE || ' and  exists (select 1 from cust_aa where aa = :1 and bb = :2 )'; -- V_CON10 WHERE문 생성
ELSE
  --V_WHERE := V_WHERE || ' and :1 = :1 and :2 = :2'; -- 이렇게 되면 using절에 파라메터 4개 적어줘야 하므로 주석처리;  
  V_WHERE := V_WHERE || ' and :1 != ''X'' and :2 != ''X'''; -- V_CON10에 해당하지 않으므로 USING문 파라메터 개수를 맞추기 위해 임의 조건절 생성
END IF

IF V_CON20 = 'Y' THEN
  V_WHERE := V_WHERE || ' and  exists (select 1 from cust_bb where aaa = :3 and  bbb = :4 and ccc = :5 AND ddd = :6)';
ELSE  
  V_WHERE := V_WHERE || ' and :3 != ''X'' and :4 != ''X'' and :5 != ''X'' and :6 != ''X''';
END IF

IF V_CON30 = 'Y' THEN
  V_WHERE := V_WHERE || ' and  exists (select 1 from cust_bbcc where  aabb = :7 and  abbb = :8 )'
ELSE  
  V_WHERE := V_WHERE || ' and :7 != ''X'' and :8 != ''X'''
END IF

V_STR := V_SQL|| V_WHERE ;

OPEN C_TYPE FOR V_STR USING AA,BB,CC,DD...생략.. -- 고정된 파라메터 나열

 


by sun [2017.03.12 23:16:53]

정말 기다렸던 답변을 주셨습니다.

감사합니다. 일요일인데.. 답변을 달아주셔서 더더욱 고맙습니다.

제가 잘못해놓은 오류도 잡으셨네요.. ^^ .. FOR ~ LOOP 안에서 조건이 중복되게 되었있었네요..

그런데.. 한가지 이해가 좀 안되는게 있어서요..

V_CON10, V_CON20, V_CON30 의 V_WHERE조건의 파라미터 갯수가 다 틀린데요..

마지막에   => OPEN C_TYPE FOR V_STR USING AA,BB,CC,DD...생략.. => 이문장에 파라미터 갯수를 어떻게 알고 대입해야 할지.. 잘 이해가 안됩니다.

너무 죄송한 말씀이지만.. 이부분 설명 좀 부탁드려도 될까요?


by jkson [2017.03.13 07:56:37]

:1 = :1과 같은 형태로 첨에 답변드렸는데 아래와 같이 수정하여야 파라메터 개수를 맞춰줄 수 있겠네요.

:1 != 'X' -- 변수값으로 올 수 없는 문자 'X'와 비교

이렇게 되면 V_CON10 일 때 파라메터 2개(:1, :2) V_CON20일 때 파라메터 4개(:3,:4,:5,:6) V_CON30일 때 파라메터 2개(:7,:8) 로 고정이죠

파라메터 개수를 고정으로 만드려고 각각의 ELSE 절에 :1 != 'X' and :2 != 'X' 와 같은 조건을 생성해준 것이구요.

USING에는 순서대로 매칭시켜주면 됩니다.(쿼리에 나타나는 바인드변수 순서대로 매칭됩니다.)


by sun [2017.03.15 23:57:32]

아.. 이제야.. 인사를 드립니다.

정신없이 일하느라. 깜빡 인사를 놓쳤습니다.

 정말 많은 도움 되었습니다.

감사드립니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입