테이블 조인의 값이 일부 중복으로 나옵니다. 0 5 1,938

by 비타민 [SQL Query] [2014.08.21 16:29:04]


안녕하세요^^ 처음 질문을 하게 되네요.
이리저리 머리를 굴려봐도 잘 되지 않아 조언을 구하고자 합니다. 조금 깁니다...

조건설명>
1. 2개의 테이블을 조인
2. SELECT 하는 데이터는 같음
3. A테이블은 본점 데이터, B테이블은 지점 데이터(B는 없을 수도 있음)
문제설명> 본사/지점 따로 했을 땐 맞게 나오는데 본사,지사를 합쳐서 SELECT하면 본사정보가 변경된 본사가 중복으로 나옵니다.


예시1(본점의 정보가 변경되었을 경우)

SELECT * 
FROM A
WHERE ((A.CODE = '02' AND A.CONFIRM_DTE = TO_CHAR(SYSDATE, 'YYYYMMDD'))
  OR (A.CODE = '02' AND A.CANCEL_DTE = TO_CHAR(SYSDATE, 'YYYYMMDD'))
  OR (A.CODE = '02' AND A.MOD_DTE = TO_CHAR(SYSDATE, 'YYYYMMDD')))
  AND A.CONFIRM_DTE IS NOT NULL    

결과

1 값 (본사 정보가 변경된 정보1)
2 값 (본사 정보가 변경된 정보2)

예시2(지점의 정보가 변경되었을 경우)

SELECT *
FROM A, B
WHERE 
((A.CODE = '02' AND B.CODE = '02' AND B.CANCEL_DTE = TO_CHAR(SYSDATE, 'YYYYMMDD'))
OR (A.CODE = '02' AND B.CODE = '02' AND B.REG_DTE = TO_CHAR(SYSDATE, 'YYYYMMDD')))
    AND A.BIZ_NO = B.BIZ_NO(+)
  AND A.AUTH_ORGAN = B.AUTH_ORGAN(+)
  AND A.REQ_DTE  = B.REQ_DTE(+)
  AND A.CONFIRM_DTE IS NOT NULL 

결과

값1(지점 정보가 변경된 본점의 정보)

 

질문예시(1과 2를 합침)

SELECT *
FROM A, B
WHERE 
((A.CODE = '02' AND A.CONFIRM_DTE = TO_CHAR(SYSDATE, 'YYYYMMDD'))
  OR (A.CODE = '02' AND A.CANCEL_DTE = TO_CHAR(SYSDATE, 'YYYYMMDD'))
  OR (A.CODE = '02' AND A.MOD_DTE = TO_CHAR(SYSDATE, 'YYYYMMDD')))
  OR((A.CODE = '02' AND B.CODE = '02' AND B.CANCEL_DTE = TO_CHAR(SYSDATE, 'YYYYMMDD'))
  OR (A.CODE = '02' AND B.CODE = '02' AND B.REG_DTE = TO_CHAR(SYSDATE, 'YYYYMMDD')))
  AND A.BIZ_NO = B.BIZ_NO(+)
  AND A.AUTH = B.AUTH(+)
  AND A.REQ_DTE  = B.REQ_DTE(+)
  AND A.CONFIRM_DTE IS NOT NULL 

결과
여기서 1-1~1-3은 동일 값, 2-1~2-3은 동일 값, 1과 2는 3개의 지점을 갖고 있음.
※ 지점은 따로 SELECT 하는 구문이 있으므로 반복되는 값 없이 나와야 함

1-1 값 (본사 정보가 변경된 본사정보1)
1-2 값 (본사 정보가 변경된
본사정보1)
1-3 값 (본사 정보가 변경된
본사정보1)
2-1 값 (본사 정보가 변경된 본사정보2)
2-2 값 (본사 정보가 변경된
본사정보2)
2-3 값 (본사 정보가 변경된
본사정보2)
값1(지점 정보가 변경된 본점의 정보)

원하는 결과

1 값 (본사 정보가 변경된 본사정보1)
2 값 (본사 정보가 변경된 본사정보2)
값1(지점 정보가 변경된 본점의 정보)

by 비주류 [2014.08.21 17:06:50]

가져오려는 값이 본점(본사?) 정보 뿐이라면 A 를 기준 테이블로 하고 B는 체크만 해도 될 것 같습니다.

아니면 그냥 GROUP BY나 DISTINCT 해야할 거구요.

예시 2번도 제대로 OUTER JOIN 되지는 않았을 것 같습니다. (B의 모든 컬럼에 (+) 붙여야...)

테스트 못해봤지만 아래 쿼리 참고해 보세요.


-- IN 부분은 각 컬럼에 인덱스 있으면 원래처럼 OR로 분리하고 PLAN에 따라 /*+ USE_CONCAT */ 사용 고려
SELECT  *
FROM    A
WHERE   A.CODE = '02'
AND     A.CONFIRM_DTE IS NOT NULL
AND     (
            TO_CHAR(SYSDATE, 'YYYYMMDD') IN (A.CONFIRM_DTE, A.CANCEL_DTE, A.MOD_DTE)
            OR EXISTS (
                        SELECT  1
                        FROM    B
                        WHERE   B.CODE = '02'
                        AND     TO_CHAR(SYSDATE, 'YYYYMMDD') IN (B.CANCEL_DTE, B.REG_DTE)
                        AND     A.BIZ_NO = B.BIZ_NO
                        AND     A.AUTH = B.AUTH
                        AND     A.REQ_DTE = B.REQ_DTE
                    )
        )

by 비타민 [2014.08.21 17:35:48]

본사정보만 가져오는게 맞고요.
말씀하신것을 응용해서 하니깐 잘 되네요. 답변 감사합니다.

 

아직 익숙하지 않은 것들이 많아서... out join에 대한 실수도 많이 하고있고요^^;;

예시로 해 주신 것 중에 1은 무엇을 의미하는건가요?


by 비주류 [2014.08.21 17:56:50]

적절히 수정하셔서 잘 된다니 다행이네요.

1값은 EXISTS 절에서 ROW 가 있다는 것만 확인하기 위한 목적으로 사용한 것으로 별다른 의미는 없습니다. (NULL, 'x', * 등으로도 대체 가능)

노파심이지만, B쪽은 적절한 INDEX 를 잘 타는지 확인이 필요할 것 같습니다.


by 마농 [2014.08.22 08:29:19]

AND 와 OR 의 차이점과 사용법에 주의하셔야 합니다.
사용하신 조건이 복잡하니 간략화하여 표현하면...
WHERE (1번조건)
   OR (2번조건)
  AND (공통조건)
이 되겠습니다. OR 를 잘못 사용하신거죠.
WHERE ( (1번조건) OR (2번조건) )
  AND (공통조건)
요렇게 괄호로 묶어주셔야 원하는 결과가 나오게 되겠지요.


by 비타민 [2014.08.22 09:55:54]

마농님 답변 감사합니다.

안그래도 어제 동일한 이야길 들었습니다.

쓰임새에 따른 사용을 주의해야겠습니다.

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