안녕하세요^^ 처음 질문을 하게 되네요.
이리저리 머리를 굴려봐도 잘 되지 않아 조언을 구하고자 합니다. 조금 깁니다...
조건설명>
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(지점 정보가 변경된 본점의 정보)
가져오려는 값이 본점(본사?) 정보 뿐이라면 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
)
)
본사정보만 가져오는게 맞고요.
말씀하신것을 응용해서 하니깐 잘 되네요. 답변 감사합니다.
아직 익숙하지 않은 것들이 많아서... out join에 대한 실수도 많이 하고있고요^^;;
예시로 해 주신 것 중에 1은 무엇을 의미하는건가요?
적절히 수정하셔서 잘 된다니 다행이네요.
1값은 EXISTS 절에서 ROW 가 있다는 것만 확인하기 위한 목적으로 사용한 것으로 별다른 의미는 없습니다. (NULL, 'x', * 등으로도 대체 가능)
노파심이지만, B쪽은 적절한 INDEX 를 잘 타는지 확인이 필요할 것 같습니다.
AND 와 OR 의 차이점과 사용법에 주의하셔야 합니다.
사용하신 조건이 복잡하니 간략화하여 표현하면...
WHERE (1번조건)
OR (2번조건)
AND (공통조건)
이 되겠습니다. OR 를 잘못 사용하신거죠.
WHERE ( (1번조건) OR (2번조건) )
AND (공통조건)
요렇게 괄호로 묶어주셔야 원하는 결과가 나오게 되겠지요.
마농님 답변 감사합니다.
안그래도 어제 동일한 이야길 들었습니다.
쓰임새에 따른 사용을 주의해야겠습니다.