dev.syw

쿼리 안의 쿼리로 단계를 나눠 복잡한 조회를 푼다.

서브쿼리

하나의 질문이 "먼저 A를 구하고, 그 결과로 B를 구한다"처럼 두 단계로 나뉠 때가 있습니다. 이때 쿼리 안에 또 다른 쿼리를 중첩하는 것을 서브쿼리라고 합니다. 조인으로 풀기 어려운 조건을 깔끔하게 표현할 수 있습니다.

학습 목표

  • WHERE 절에서 서브쿼리로 조건을 만듭니다.
  • INEXISTS 로 존재 여부를 검사합니다.
  • 스칼라 서브쿼리로 단일 값을 끌어옵니다.
  • FROM 절의 파생 테이블을 활용합니다.

WHERE 절 서브쿼리

-- 평균 나이보다 많은 사용자
SELECT name, age
FROM users
WHERE age > (SELECT AVG(age) FROM users);

괄호 안 서브쿼리가 먼저 실행되어 평균 나이(하나의 값)를 반환하고, 바깥 쿼리가 그 값과 비교합니다. 이렇게 값 하나를 돌려주는 서브쿼리를 스칼라 서브쿼리라고 합니다.

IN — 목록 안에 있는지

-- 한 번이라도 주문한 사용자
SELECT name
FROM users
WHERE id IN (SELECT DISTINCT user_id FROM orders);

서브쿼리가 여러 값을 반환하면 IN 으로 그 목록과 비교합니다.

-- 10만 원 이상 주문이 있는 사용자만
SELECT name
FROM users
WHERE id IN (
  SELECT user_id FROM orders WHERE amount >= 100000
);

EXISTS — 존재하기만 하면

SELECT u.name
FROM users AS u
WHERE EXISTS (
  SELECT 1 FROM orders AS o WHERE o.user_id = u.id
);

EXISTS 는 서브쿼리에 행이 하나라도 있으면 참입니다. 바깥 행의 값(u.id)을 서브쿼리가 참조하는 형태를 상관 서브쿼리라고 하며, 행마다 평가됩니다.

💡 TIP — "존재하는지"만 따질 때는 IN 보다 EXISTS 가 유리한 경우가 많습니다. 일치하는 첫 행을 찾으면 바로 멈추기 때문입니다. 반대로 서브쿼리 결과에 NULL 이 섞이면 NOT IN 은 예상과 다르게 동작할 수 있어, 이럴 땐 NOT EXISTS 가 안전합니다.

스칼라 서브쿼리를 SELECT 에서

SELECT
  u.name,
  (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) AS 주문수
FROM users AS u;

SELECT 절에 단일 값 서브쿼리를 넣어 각 행마다 계산된 값을 컬럼처럼 붙일 수 있습니다.

⚠️ 주의 — 스칼라 서브쿼리는 반드시 값 하나(1행 1열)만 반환해야 합니다. 여러 행이 나오면 오류가 납니다. 또한 행마다 실행되므로 데이터가 많으면 조인보다 느려질 수 있습니다.

FROM 절 파생 테이블

서브쿼리 결과를 임시 테이블처럼 다뤄 다시 조회할 수 있습니다. 반드시 별칭이 필요합니다.

-- 사용자별 총액을 먼저 구한 뒤, 그중 상위만
SELECT t.user_id, t.총액
FROM (
  SELECT user_id, SUM(amount) AS 총액
  FROM orders
  GROUP BY user_id
) AS t
WHERE t.총액 >= 500000
ORDER BY t.총액 DESC;

집계 결과를 한 번 더 거르거나 조인할 때 자주 쓰는 패턴입니다.

요약

  • 서브쿼리는 쿼리 안의 쿼리로, 단계를 나눠 문제를 풉니다.
  • 단일 값은 스칼라 서브쿼리, 여러 값은 IN, 존재 여부는 EXISTS 로 검사합니다.
  • 상관 서브쿼리는 바깥 행을 참조하며 행마다 평가됩니다.
  • FROM 절 파생 테이블은 중간 결과를 임시 테이블처럼 활용하며 별칭이 필요합니다.

연습문제

  1. 전체 주문 평균 금액보다 큰 금액의 주문만 조회하세요.
  2. 주문 이력이 있는 사용자의 이름을 IN 으로 구하세요.
  3. 각 사용자 옆에 그 사람의 주문 건수를 붙여 출력하세요.
  4. 사용자별 총 주문액을 구한 뒤, 총액 30만 원 이상인 사용자만 보여 주세요(파생 테이블).

힌트 — 1번은 스칼라 서브쿼리, 2번은 IN (SELECT ...), 3번은 SELECT 절 서브쿼리, 4번은 FROM (SELECT ...) 입니다.

💡 연습문제 풀이

불러오는 중…

함께 보면 좋은 자료

댓글 0

MySQL” 강좌에 대한 댓글입니다.

댓글을 작성하려면 로그인이 필요합니다.