SQL/SQLD

#15 서브쿼리(Subquery)

sundori 2025. 4. 13. 16:39

목차

    서브쿼리(Subquery)

    서브쿼리는 말 그대로 메인이 아닌 보조(서브) 역할을 하는 쿼리를 뜻한다.
    즉, 하나의 메인 SQL문 안에 포함되어 실행되는 SELECT 문을 말한다.

    보통 메인 쿼리가 실행되기 전에
    서브쿼리가 먼저 실행되어 그 결과가 조건, 조회 값, 테이블처럼 사용된다.
    그래서 서브쿼리는 SELECT, FROM, WHERE, HAVING 절 등 다양한 위치에 들어갈 수 있다.

     

    예를들어,

    SELECT name
    FROM students
    WHERE score > (SELECT AVG(score) FROM students);

    → 이때 괄호 안의 SELECT AVG(score)... 부분이 바로 서브쿼리이다.
    메인 쿼리는 이름을 가져오는 역할이고,
    서브쿼리는 평균 점수를 구해서 메인 쿼리의 조건으로 사용되는 것이다.

     

    ✅ 서브쿼리의 종류

    위치 서브쿼리 종류 설명
    SELECT 절 스칼라 서브쿼리(Scalar Subquery) 단일 값을 SELECT 절에서 조회할 때 사용
    FROM 절 인라인 뷰(Inline View) SELECT 결과를 테이블처럼 사용
    WHERE/ HAVING 절 중첩 서브쿼리(Nested Subquery) 조건절에서 결과를 비교하기 위해 사용

     

    스칼라 서브쿼리(SELECT 절)

    SELECT 안에 들어가서 단 하나의 값을 조회
    → 꼭 단일 값만 반환해야 함 (row 1, col 1)

     

    📌 예제

    SELECT name,
    	(SELECT MAX(score) FROM scores) AS max_score
    FROM students;

    ✅ 모든 학생 행에 대해 최고 점수가 함께 표시됨


    인라인 뷰(FROM 절)

    FROM 안에 SELECT 문을 넣어서 가상의 테이블처럼 사용하는 것

     

    📌 예제

    SELECT name, avg_score
    FROM (
        SELECT student_id, AVG(score) AS avg_score
        FROM scores
        GROUP BY student_id
    ) AS avg_table
    JOIN students ON avg_table.student_id = students.student_id;

    ✅ 학생별 평균 점수를 구한 결과를 FROM 안에서 테이블처럼 사용한 것


    중첩 서브쿼리(WHERE/HAVING 절)

    조건문 안에 들어가서 필터링 기준이 되는 쿼리

     

    📌 예제

    SELECT name
    FROM students
    WHERE student_id IN (
        SELECT student_id1
        FROM scores
        WHERE subject = '수학'
    );

    ✅ 수학 점수가 있는 학생만 조회됨 → 서브쿼리가 조건의 일부가 됨

     

    ✅ 중첩 서브쿼리 추가 팁

    WHERE 절, HAVING 절 등 조건에 포함된 서브쿼리를 통틀어 중첩 서브쿼리(Nested Subquery)라고 한다.
    이 중에서 메인쿼리와 독립적인지, 참조하는지에 따라 아래 두 가지로 나뉜다.

    비연관 서브쿼리(Non-Correlated Subquery)

    메인 쿼리와 독립적으로 한 번만 실행되는 서브쿼리

     

    항목 설명
    의존성 메인 쿼리와 전혀 관계 없음
    실행 횟수 단 한 번 실행되고, 그 결과로 조건 판단
    성능 일반적으로 빠름
    주로 사용되는 곳 IN, =, NOT IN, >=, ANY, ALL, HAVING, WHERE

     

    📌 예제

    SELECT name
    FROM students
    WHERE score >= (
      SELECT AVG(score) FROM students
    );

     

    • SELECT AVG(score)...는 한 번만 실행됨
    • 메인 쿼리와 별개로 동작함 → 비연관 서브쿼리

    연관 서브쿼리(Correlated Subquery)

    서브쿼리 안에서 메인 쿼리의 값을 참조하는 서브쿼리

     

     

    그냥 서브쿼리 내에 메인쿼리의 컬럼이 존재하면 연관 서브 쿼리이다. 비연관 서브쿼리는 그 반대이다.

    항목 설명
    의존성 서브 쿼리가 메인쿼리의 값을 참조함
    실행 횟수 메인 쿼리의 행 수만큼 반복 실행됨
    성능 느릴 수 있음(행마다 반복하기에)
    주로 사용되는 곳 행마다 조건을 다르게 줄 때, 조건이 복잡할 때

     

    📌 예제

    SELECT s1.name
    FROM students s1
    WHERE score > (
      SELECT AVG(score)
      FROM students s2
      WHERE s2.class_id = s1.class_id
    );
    • s1.class_id를 서브쿼리에서 사용하고 있음 → 연관 서브쿼리
    • 각 행마다 다른 조건으로 비교됨

    ✅ 실무 팁

    • 연관 서브쿼리는 성능상 부담이 될 수 있으므로, JOIN으로 바꾸는 게 더 효율적일 때도 많음.
    • 하지만 조건이 매우 동적인 경우에는 연관 서브쿼리가 더 자연스럽게 표현됨.

    🧠 한 줄 정리

    비연관 서브쿼리는 독립적으로 한 번만 실행되는 조건용 쿼리,
    연관 서브쿼리는 메인 쿼리의 각 행과 연결되어 반복적으로 실행되는 동적 쿼리다.

    단일 행 , 다중 행, 다중 컬럼 서브쿼리

    서브쿼리를 **결과 형태(반환 값)**에 따라 분류하는
    ✅ 단일 행 서브쿼리
    ✅ 다중 행 서브쿼리
    ✅ 다중 컬럼 서브쿼리
    이 개념은 서브쿼리의 비교 연산자 선택, 오류 방지, 문법 설계에 아주 중요하다.

     

     

    결과가 1행 1열인 서브쿼리

     

    ✅ 예제

    SELECT name
    FROM students
    WHERE score > (
      SELECT AVG(score)
      FROM students
    );
    • AVG(score)는 1개의 숫자 → 단일 값
    • 비교 연산자: =, >, < 등 사용 가능

    ❗ 에러 예시

    SELECT name
    FROM students
    WHERE score = (
      SELECT score
      FROM scores
      WHERE subject = '수학'
    );

    → 수학 과목 점수가 여러 개 있으면 "서브쿼리에서 둘 이상의 행을 반환했습니다" 오류 발생!

     

    2️⃣ 다중 행 서브쿼리 (Multi-Row Subquery)

    **결과가 여러 행(1열)**인 서브쿼리

     

    ✅ 예제

    SELECT name
    FROM students
    WHERE student_id IN (
      SELECT student_id1
      FROM scores
      WHERE subject = '수학'
    );
    • IN, ANY, ALL, EXISTS 같은 연산자가 필요함
    IN 여러 값 중 하나와 일치
    ANY 서브쿼리 결과 중 하나라도 만족
    ALL 서브쿼리 결과 모두를 만족해야 함
    -- ANY 예시
    SELECT name
    FROM students
    WHERE score > ANY (
      SELECT score FROM scores WHERE subject = '영어'
    );
    
    -- ALL 예시
    SELECT name
    FROM students
    WHERE score > ALL (
      SELECT score FROM scores WHERE subject = '과학'
    );

     

     

    3️⃣ 다중 컬럼 서브쿼리 (Multi-Column Subquery)

    **서브쿼리 결과가 여러 열(2열 이상)**인 경우

     

    ✅ 예제

    SELECT name
    FROM students
    WHERE (student_id, class_id) IN (
      SELECT student_id, class_id
      FROM enrollments
    );
    • 두 개의 컬럼을 동시에 비교해야 할 때 유용
    • 주로 (A, B) IN (SELECT A, B ...) 형태로 사용

    🧠 정리 한줄

    서브쿼리를 사용할 땐 "무엇을 반환하느냐"가 가장 중요하다.
    단일 값이면 =, 여러 값이면 IN, 여러 컬럼이면 (a,b) IN (...)처럼
    형태에 맞는 연산자를 반드시 사용해야 오류 없이 정확한 쿼리를 만들 수 있다.


    ✅ 서브쿼리 위치 총정리 표

    위치(절) 서브쿼리 종류 설명
    SELECT 스칼라 서브쿼리 SELECT 결과에 단일 값을 컬럼처럼 포함
    ORDER BY 스칼라 서브쿼리 정렬 기준으로 단일 값을 넣을 수 있음
    FROM 인라인 뷰 SELECT 결과를 테이블처럼 사용
    WHERE 중첩 서브쿼리 조건 판단용. IN, =, EXISTS, ANY, ALL 등과 함께
    HAVING 중첩 서브쿼리 그룹 조건 판단용
    UPDATE - SET 절 스칼라 서브쿼리 특정 컬럼을 서브쿼리 결과값으로 갱신
    UPDATE - WHERE 절 중첩 서브쿼리 어떤 행을 업데이트할지 조건으로 사용
    DELETE - WHERE 절 중첩 서브쿼리 삭제 조건 지정
    INSERT - VALUES 절 스칼라 서브쿼리 삽입 값으로 서브쿼리 결과 사용
    INSERT - SELECT 인라인 뷰 FROM 안에 서브쿼리로 가져와 INSERT
    MERGE 절 (Oracle 등) 다양함 조건 비교 및 값 설정 시 서브쿼리 사용d

     

    728x90

    'SQL > SQLD' 카테고리의 다른 글

    #17 집합 연산자  (0) 2025.04.14
    #16 뷰(View)  (0) 2025.04.14
    #14 JOIN  (0) 2025.04.13
    #13 ORDER BY  (0) 2025.04.13
    #12 GROUP BY, HAVING 절  (0) 2025.04.13