SQLD · SQL 개발자

조인 — 등가·비등가·외부 조인

조인 문제는 대부분 결과 행 수를 묻습니다. 어떤 조인이 어느 쪽 행을 보존하는지, 조인 조건을 ON 에 두느냐 WHERE 에 두느냐에 따라 외부 조인이 내부 조인으로 바뀌는지를 따질 수 있으면 됩니다. 카티션 곱이 나오는 조건도 자주 나옵니다.

이 주제에서 다루는 내용

  • INNER JOIN 과 등가·비등가 조인
  • LEFT, RIGHT, FULL OUTER JOIN 이 보존하는 행
  • CROSS JOIN 과 카티션 곱이 생기는 조건
  • NATURAL JOIN 과 USING 절의 제약
  • SELF JOIN 과 별칭 사용

자주 틀리는 지점

  • 외부 조인에서 조건을 WHERE 에 두어 내부 조인이 되는 것을 놓치는 경우. 가장 많이 틀리는 지점입니다.
  • NATURAL JOIN 에서 같은 이름 컬럼에 별칭을 붙이면 오류가 난다는 점.
  • FULL OUTER JOIN 의 결과 행 수를 양쪽 행 수의 합으로 세는 실수.

연습문제 3문항

아래 문항은 오리지널 문제입니다. 기출문제가 아닙니다.

  1. 다음 테이블과 SQL을 보고, 실행 결과를 올바르게 설명한 것은? [CUSTOMER 테이블] CUST_ID | CUST_NAME | CITY --------|-----------|------ 1 | 김철수 | 서울 2 | 이영희 | 부산 3 | 박민수 | NULL 4 | 최지은 | 대구 [ORDER 테이블] ORDER_ID | CUST_ID | ORDER_AMT ---------|---------|---------- 101 | 1 | 50000 102 | 1 | 30000 103 | 2 | 40000 104 | 5 | 60000 105 | NULL | 20000 [SQL] SELECT C.CUST_NAME, COUNT(O.ORDER_ID) AS ORDER_COUNT FROM CUSTOMER C LEFT JOIN ORDER O ON C.CUST_ID = O.CUST_ID WHERE C.CITY IS NOT NULL GROUP BY C.CUST_NAME HAVING COUNT(O.ORDER_ID) = (SELECT COUNT(*) FROM ORDER WHERE CUST_ID = 1);

    • A. 김철수 고객만 조회되며, ORDER_COUNT는 2이다.
    • B. 김철수와 이영희 고객이 조회되며, 각각의 ORDER_COUNT는 2, 1이다.
    • C. 박민수 고객도 포함되어 총 3명이 조회되며, 박민수의 ORDER_COUNT는 0이다.
    • D. CITY가 NULL인 박민수는 WHERE 조건에 의해 제외되고, 최지은은 주문이 없어 HAVING 조건에서 제외된다.

    정답: A

    해설. 서브쿼리 (SELECT COUNT(*) FROM ORDER WHERE CUST_ID = 1)는 2를 반환한다. WHERE C.CITY IS NOT NULL 조건으로 박민수(CITY=NULL)가 제외되고, LEFT JOIN으로 김철수(2건), 이영희(1건), 최지은(0건)이 남는다. HAVING 조건에서 ORDER_COUNT = 2인 김철수만 선택된다. 이영희는 주문 1건으로 HAVING 조건 불만족하여 제외된다.

  2. 다음 두 테이블과 SQL문을 보고 실행 결과로 옳은 것을 고르시오. [PRODUCT 테이블] PROD_ID | PROD_NAME | CATEGORY | PRICE ---------|-----------|----------|------- P001 | 노트북 | COMPUTER | 1200000 P002 | 마우스 | COMPUTER | 25000 P003 | 책상 | FURNITURE| 150000 P004 | 의자 | FURNITURE| 80000 P005 | 키보드 | COMPUTER | NULL [SALES 테이블] SALE_ID | PROD_ID | QUANTITY | SALE_DATE --------|---------|----------|---------- S001 | P001 | 2 | 2024-01-15 S002 | P002 | 5 | 2024-01-20 S003 | P003 | 1 | 2024-02-10 S004 | P002 | 3 | 2024-02-15 S005 | P004 | 2 | 2024-03-05 SELECT P.CATEGORY, COUNT(*) AS PROD_COUNT, COALESCE(SUM(S.QUANTITY), 0) AS TOTAL_QTY FROM PRODUCT P LEFT JOIN SALES S ON P.PROD_ID = S.PROD_ID WHERE P.PRICE IS NOT NULL GROUP BY P.CATEGORY HAVING COUNT(S.SALE_ID) >= 1 ORDER BY TOTAL_QTY DESC;

    • A. COMPUTER | 2 | 10 / FURNITURE | 2 | 3
    • B. FURNITURE | 2 | 3 / COMPUTER | 2 | 10
    • C. COMPUTER | 3 | 10 / FURNITURE | 2 | 3
    • D. COMPUTER | 2 | 8 / FURNITURE | 2 | 3

    정답: C

    해설. 1) WHERE P.PRICE IS NOT NULL로 PRICE가 NULL인 P005(키보드)가 제외되어 PRODUCT는 P001,P002,P003,P004만 남는다. 2) LEFT JOIN SALES 결과: COMPUTER는 P001(S001) 1행, P002(S002,S004) 2행으로 총 3행, FURNITURE는 P003(S003) 1행, P004(S005) 1행으로 총 2행이 된다. 3) GROUP BY CATEGORY 후 COUNT(*)는 조인된 행 수를 세므로 COMPUTER=3, FURNITURE=2다. 4) COALESCE(SUM(S.QUANTITY),0)은 COMPUTER=2+5+3=10, FURNITURE=1+2=3이다. 5) HAVING COUNT(S.SALE_ID)>=1은 두 카테고리 모두 판매 실적이 있어 통과한다. 6) ORDER BY TOTAL_QTY DESC로 10인 COMPUTER가 먼저, 3인 FURNITURE가 뒤에 온다. 따라서 결과는 'COMPUTER | 3 | 10', 'FURNITURE | 2 | 3'으로 C가 정답이다. - A: COMPUTER의 COUNT(*)를 3이 아닌 2로 잘못 계산했다. COUNT(*)는 제품 종류 수가 아니라 조인된 행 수를 세므로 P002의 2건 판매가 각각 별도 행이 되어 3이 맞다. - B: 값은 A와 동일하게 틀렸을 뿐 아니라 ORDER BY TOTAL_QTY DESC 정렬 순서까지 반대로 되어 있다. - D: TOTAL_QTY를 8로 잘못 계산했다. COMPUTER 수량 합은 2+5+3=10이며, COUNT(*)도 2가 아닌 3이다.

  3. 다음 고객(CUSTOMER)과 계좌(ACCOUNT) 테이블에서 LEFT OUTER JOIN을 사용한 SQL문의 실행 결과로 옳은 것은? [CUSTOMER 테이블] CUST_ID | CUST_NAME | PHONE 001 | 김철수 | 010-1111-1111 002 | 이영희 | 010-2222-2222 003 | 박민수 | NULL [ACCOUNT 테이블] ACCT_ID | CUST_ID | BALANCE A001 | 001 | 100000 A002 | 001 | 50000 A003 | 002 | 200000 SELECT C.CUST_NAME, A.ACCT_ID, A.BALANCE FROM CUSTOMER C LEFT OUTER JOIN ACCOUNT A ON C.CUST_ID = A.CUST_ID WHERE A.BALANCE >= 100000;

    • A. 김철수 | A001 | 100000 이영희 | A003 | 200000
    • B. 김철수 | A001 | 100000 김철수 | A002 | 50000 이영희 | A003 | 200000 박민수 | NULL | NULL
    • C. 김철수 | A001 | 100000 이영희 | A003 | 200000 박민수 | NULL | NULL
    • D. 김철수 | A001 | 100000 김철수 | A002 | 50000 이영희 | A003 | 200000

    정답: A

    해설. LEFT OUTER JOIN으로 모든 고객이 조회되지만, WHERE절의 A.BALANCE >= 100000 조건이 JOIN 이후에 적용되어 실질적으로 INNER JOIN과 동일한 결과가 나타납니다. 박민수는 계좌가 없어 A.BALANCE가 NULL이므로 WHERE 조건에서 제외되고, 김철수의 A002 계좌(50000원)도 조건에 맞지 않아 제외됩니다. 따라서 조건을 만족하는 김철수의 A001 계좌(100000원)와 이영희의 A003 계좌(200000원)만 결과에 포함됩니다.

SQLD 연습문제 전체 풀기

같은 시험의 다른 주제