ORA-01799: 열은 하위 질의에 포괄 조인될 수 없습니다. (ORA-01799 a column may not be outer-joined to a subquery)

ORA-01799: 열은 하위 질의에 포괄 조인될 수 없습니다. (ORA-01799: a column may not be outer-joined to a subquery) 해당 오류는 오라클 아우터 조인(외부 조인)에서 서브쿼리를 시도하려고 할 때 발생합니다. 해당 오류를 수정하는 방법에 대해 알아보도록 합시다.

아참, 오류에서 말하는 포괄조인이 외부조인을 뜻한답니다! 최근에는 모두 외부조인이라고 해석하는데, 당시에는 포괄이라고 해석을 하였습니다.

2가지 예시를 살펴볼 것인데요, 첫 번째는 레프트 조인, 두 번째는 풀 아우터 조인입니다.

하위 질의 포괄 조인 ORA-01799: 열은 하위 질의에 포괄 조인될 수 없습니다.

해당 오류는 문자 그대로 아우터 조인에서 서브쿼리를 사용하려고 시도할 때에 발생합니다. 이 때에는 하위 질의에 해당하는 컬럼을 뷰로 바꾸어 해결할 수 있답니다. 예시를 바로 살펴보겠습니다!

직원정보 테이블에서 'KING'과 같은 부서에서 일하고 있는 경우 표시를 하려고 하는데, 다음과 같이 ORA-01799 오류가 발생합니다.

SELECT EMPNO,ENAME,EMP.DEPTNO, DECODE (DEPT.DEPTNO, NULL, NULL, 'Working With KING')
  FROM    EMP
       LEFT JOIN
          DEPT
       ON DEPT.DEPTNO = EMP.DEPTNO
          AND DEPT.DEPTNO = (SELECT MAX (DEPTNO)
                               FROM EMP
                              WHERE ENAME = 'KING');

ERROR at line 1:
ORA-01799: a column may not be outer-joined to a subquery

다음처럼 해당 컬럼을 바꾸어 조회하여 해결할 수 있답니다.

SELECT EMPNO,ENAME,EMP.DEPTNO, DECODE (DEPT.DEPTNO, NULL, NULL, 'Working With KING')
  FROM    EMP
       LEFT JOIN
          (SELECT *
             FROM DEPT
            WHERE DEPTNO = (SELECT MAX (DEPTNO)
                              FROM EMP
                             WHERE ENAME = 'KING')) DEPT
       ON DEPT.DEPTNO = EMP.DEPTNO;

     EMPNO ENAME                    DEPTNO DECODE(DEPT.DEPTNO,NULL,NULL,'WORK
---------- -------------------- ---------- ----------------------------------
      7839 KING                         10 Working With KING
      7934 MILLER                       10 Working With KING
      7782 CLARK                        10 Working With KING
      7900 JAMES                        30
      7844 TURNER                       30
      7654 MARTIN                       30
      7521 WARD                         30
      7499 ALLEN                        30
      7698 BLAKE                        30
      7876 ADAMS                        20
      7369 SMITH                        20
      7902 FORD                         20
      7788 SCOTT                        20
      7566 JONES                        20

14 rows selected.

하위 질의 풀 아우터 조인 시 ORA-01799 오류

ORA-01799 열은 하위 질의에 포괄 조인될 수 없습니다

ORA-01799 오류는 레프트 아우터 조인과 라이트 아웃 조인을 오라클 조인인 (+) 기호와 함께 표현한 쿼리에서 발생하며, 이 글을 보고 계신 여러분의 쿼리에도 (+) 사인이 있을 것입니다. 해결 방법은 오라클 조인에서 ANSI 조인으로 변경하는 방법 또는 뷰를 먼저 조회하는 방법이 있습니다.

  • 오라클 조인 => ANSI 조인 변경하기
  • 뷰 조회하기

문제가 발생하는 예시 쿼리는 다음과 같습니다. 해당 쿼리는 실행 시 오류가 발생합니다.

SELECT *
         FROM EMP, DEPT
        WHERE DEPT.DEPTNO(+) = EMP.DEPTNO
              AND DEPT.DEPTNO(+) IN (SELECT '10' FROM DUAL
                                     UNION ALL
                                     SELECT '20' FROM DUAL)
     ORDER BY EMP.DEPTNO, DEPT.DEPTNO, EMPNO;

ERROR at line 7:
ORA-01799: a column may not be outer-joined to a subquery

오라클 조인에서 ANSI 조인으로 변경하여 해결하기

ORA-01799 오류를 오라클 조인에서 ANSI 조인으로 변경

ANSI 조인으로 변경하여 해결하는 방법입니다. 아우터 조인 형식으로 수정한 간단한 예시를 추가합니다.

--ANSI 조인으로 해결 방법

SELECT *
  FROM    EMP
       LEFT JOIN
          DEPT
       ON DEPT.DEPTNO = EMP.DEPTNO
          AND DEPT.DEPTNO IN (SELECT '10' FROM DUAL
                              UNION ALL
                              SELECT '20' FROM DUAL)       
ORDER BY EMP.DEPTNO, DEPT.DEPTNO, EMPNO;

--14 rows selected.

인라인뷰를 생성하여 해결하기

인라인뷰 형태로 변경하여 해결하는 방법입니다. 두 테이블을 바로 조인하지 않고 아우터 조인의 대상이 되는 테이블을 뷰 형태로 가공하였습니다.

--인라인 뷰로 해결 방법
SELECT *
    FROM EMP,
         (SELECT *
            FROM DEPT
           WHERE DEPTNO IN (SELECT '10' FROM DUAL
                            UNION ALL
                            SELECT '20' FROM DUAL)) DEPTVIEW
   WHERE DEPTVIEW.DEPTNO(+) = EMP.DEPTNO
ORDER BY EMP.DEPTNO, DEPTVIEW.DEPTNO, EMPNO;

--14 rows selected.

(+) 기호를 그냥 생략하면 어떻게 될까?

오라클 조인 (+) 생략

오류가 발생한다고 (+) 조인 기호를 그냥 지워버리면 전혀 다른 결과를 조회합니다. 오라클 아우터 조인은 WHERE부터 시작하기에 조인 컬럼의 (+) 여부에 따라 조건이 전혀 다르게 해석이 되는 점을 기억해 주세요. 다음 쿼리는 (+)를 생략하였을 때 어떠한 ANSI 조인 결과와 동일한지 보여드리고 있습니다.

  SELECT *
    FROM EMP, DEPT
   WHERE DEPT.DEPTNO(+) = EMP.DEPTNO
         AND DEPT.DEPTNO IN (SELECT '10' FROM DUAL
                             UNION ALL
                             SELECT '20' FROM DUAL)
ORDER BY EMP.DEPTNO, DEPT.DEPTNO, EMPNO;

--8 rows selected.

위의 쿼리는 다음 ANSI조인과 조회 결과가 같습니다.

  SELECT *
    FROM EMP LEFT JOIN DEPT ON DEPT.DEPTNO = EMP.DEPTNO
   WHERE DEPT.DEPTNO IN (SELECT '10' FROM DUAL
                         UNION ALL
                         SELECT '20' FROM DUAL)
ORDER BY EMP.DEPTNO, DEPT.DEPTNO, EMPNO;

--8 rows selected.

댓글