🧚 잠깐만요! Beekeeper Studio는 빠르고 현대적인 오픈 소스 데이터베이스 GUI예요 다운로드
2026년 1월 7일 작성자: Lucas Gray

서브쿼리는 다른 쿼리 안에 중첩된 쿼리예요. CTE(공통 테이블 표현식)는 같은 내부 쿼리를 WITH로 문장 맨 앞에 옮기고 이름을 붙인 것이라, 긴 쿼리를 단계별로 읽을 수 있어요. 예제는 PostgreSQL, MySQL, SQLite, SQL Server에서 동작해요.

CTE와 서브쿼리 사용법

서브쿼리는 사용되는 위치에 그대로 들어가요. FROM에서는 테이블처럼 동작하고, WHERE나 SELECT에서는 값이나 목록을 제공해요. CTE는 먼저 정의한 뒤, 이어지는 쿼리에서 테이블처럼 사용해요:

-- Subquery: written where it's used
SELECT columns FROM (SELECT ...) AS name;

-- CTE: named first, then used like a table
WITH name AS (SELECT ...)
SELECT columns FROM name;
SELECT n * 2 AS doubled FROM (SELECT 21 AS n) AS numbers;
-- Output: 42

WITH numbers AS (SELECT 21 AS n)
SELECT n * 2 AS doubled FROM numbers;
-- Output: 42

실제 테이블에서는 두 형태가 같은 행을 반환해요. 같은 필터를 두 방식으로 작성하면 이렇습니다:

-- Input: people
-- first_name | last_name | job      | favorite_food
-- -----------+-----------+----------+--------------
-- Matthew    | Ortiz     | Chef     | cheese
-- Matt       | Novak     | Pilot    | pizza
-- Mattie     | Brooks    | Engineer | cheese
-- Priya      | Nair      | Teacher  | cheese

-- Subquery
SELECT *
FROM (SELECT first_name, last_name, job FROM people WHERE favorite_food = 'cheese') AS cheese_lovers
WHERE first_name LIKE 'Matt%';

-- CTE
WITH cheese_lovers AS (
  SELECT first_name, last_name, job FROM people WHERE favorite_food = 'cheese'
)
SELECT * FROM cheese_lovers
WHERE first_name LIKE 'Matt%';

-- Output of both:
-- first_name | last_name | job
-- -----------+-----------+---------
-- Matthew    | Ortiz     | Chef
-- Mattie     | Brooks    | Engineer

알아 둘 규칙

  • CTE는 한 문장 동안만 유지돼요. WITH 바로 뒤의 쿼리는 사용할 수 있지만, 다음 문장은 사용할 수 없어요. 여러 쿼리에서 결과를 유지하려면 임시 테이블이나 뷰를 사용하세요.
  • FROM의 서브쿼리에는 이름을 붙이세요. 위의 AS numbers처럼요. MySQL과 SQL Server는 이름이 없으면 오류를 내요.
  • 단일 값으로 쓰이는 서브쿼리는 한 행만 반환해야 해요:
SELECT (SELECT 1 UNION ALL SELECT 2) AS n;
-- ERROR: more than one row returned by a subquery used as an expression
-- (SQLite doesn't complain: it quietly uses the first row, 1)
  • 속도는 보통 같아요. 데이터베이스는 대개 한 번만 쓰이는 CTE를 동등한 서브쿼리와 같은 방식으로 실행 계획을 세우므로, 더 읽기 좋은 쪽을 고르세요.

대체 문법

자기 자신을 참조하는 CTE(아래 참고)는 WITH RECURSIVE로 작성해요:

-- In SQL Server, leave out RECURSIVE
WITH RECURSIVE counter AS (
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1 FROM counter WHERE n < 3
)
SELECT n FROM counter;

-- Output:
-- n
-- -
-- 1
-- 2
-- 3

SQL Server에서는 WITH 앞의 문장이 세미콜론으로 끝나야 해요. 그래서 T-SQL 코드에서는 CTE를 ;WITH로 시작하는 경우가 많아요.

언제 서브쿼리 대신 CTE를 써야 할까요?

작은 단계 하나라면 서브쿼리로 충분해요. 쿼리에 단계가 여러 개이거나, 같은 결과가 두 번 필요하거나, 자기 자신을 참조해야 할 때는 CTE로 바꾸세요.

계산된 값 하나로 필터링하기

평균 주문 금액처럼 내부 쿼리가 비교할 값이나 목록만 만들어 낸다면, WHERE 안의 서브쿼리가 가장 짧게 작성하는 방법이에요. CTE도 되지만 아무도 필요 없는 이름이 하나 늘어날 뿐이에요.

긴 쿼리를 이름 붙은 단계로 나누기

쿼리에 여러 단계가 있다면(고객별 합계, 그다음 상위 몇 명, 그다음 최종 목록) 각 단계에 이름을 붙이세요. 하나의 WITH 뒤에 여러 CTE를 쉼표로 구분해 나열하면, 각 CTE는 앞의 CTE를 사용할 수 있고 쿼리를 안쪽에서 바깥쪽이 아니라 위에서 아래로 읽을 수 있어요.

같은 결과를 여러 번 사용하기

한 문장에서 CTE를 원하는 만큼 참조할 수 있어서, 두 번 필요한 결과(합계 목록과 그 평균, 또는 각 합계와 총합계)를 한 번만 작성하면 돼요. 서브쿼리라면 내부 쿼리 전체를 복사해야 해요.

계층 구조 탐색하기

자기 자신을 참조할 수 있는 건 CTE뿐이에요. 재귀 CTE는 일부 행에서 시작해 새 행이 더 나오지 않을 때까지 테이블에 계속 다시 조인해요. 조직도나 카테고리 트리를 탐색하거나, 숫자나 날짜 시퀀스를 생성할 때 이렇게 해요.

CTE와 서브쿼리 실전 예제

카테고리 평균보다 비싼 상품

서브쿼리가 바깥 쿼리의 p.category를 참조하므로, 각 상품의 카테고리별로 계산돼요(상관 서브쿼리):

-- Input: products
-- name          | category  | price
-- --------------+-----------+-------
-- Desk Lamp     | Lighting  | 24.99
-- Floor Lamp    | Lighting  | 89.00
-- Office Chair  | Furniture | 149.00
-- Standing Desk | Furniture | 399.00
-- Bookshelf     | Furniture | 120.00

SELECT name, category, price
FROM products p
WHERE price > (
  SELECT AVG(price) FROM products WHERE category = p.category
)
ORDER BY category, name;

-- Output:
-- name          | category  | price
-- --------------+-----------+-------
-- Standing Desk | Furniture | 399.00
-- Floor Lamp    | Lighting  | 89.00

카테고리별 베스트셀러 상품

이름이 붙은 세 단계로 나눠요. 상품별 판매 수량을 합산하고, 카테고리 안에서 순위를 매긴 뒤, 1위만 남겨요:

-- Input: sales
-- id | product      | category  | units
-- ---+--------------+-----------+------
-- 1  | Desk Lamp    | Lighting  | 3
-- 2  | Floor Lamp   | Lighting  | 5
-- 3  | Desk Lamp    | Lighting  | 4
-- 4  | Office Chair | Furniture | 2
-- 5  | Bookshelf    | Furniture | 6

WITH product_totals AS (
  SELECT category, product, SUM(units) AS units
  FROM sales
  GROUP BY category, product
),
ranked AS (
  SELECT category, product, units,
         RANK() OVER (PARTITION BY category ORDER BY units DESC) AS place
  FROM product_totals
)
SELECT category, product, units
FROM ranked
WHERE place = 1
ORDER BY category;

-- Output:
-- category  | product   | units
-- ----------+-----------+------
-- Furniture | Bookshelf | 6
-- Lighting  | Desk Lamp | 7

지역별 매출 비중

region_totals는 두 번 쓰여요. 한 번은 행을 위해, 또 한 번은 총합계를 구하는 서브쿼리 안에서요:

-- Input: orders
-- id | region | amount
-- ---+--------+--------
-- 1  | North  | 1200.00
-- 2  | South  | 450.00
-- 3  | North  | 300.00
-- 4  | West   | 800.00
-- 5  | South  | 250.00

WITH region_totals AS (
  SELECT region, SUM(amount) AS total
  FROM orders
  GROUP BY region
)
SELECT
  region,
  total,
  ROUND(100.0 * total / (SELECT SUM(total) FROM region_totals), 1) AS pct_of_sales
FROM region_totals
ORDER BY total DESC;

-- Output:
-- region | total   | pct_of_sales
-- -------+---------+-------------
-- North  | 1500.00 | 50.0
-- West   | 800.00  | 26.7
-- South  | 700.00  | 23.3

서브쿼리로 작성하면 GROUP BY 쿼리가 두 번 나타나요.

직원의 관리자 체인

한 직원에서 시작해 manager_id가 끝날 때까지 위로 따라가요:

-- Input: employees
-- id | name      | manager_id
-- ---+-----------+-----------
-- 1  | Maya Chen | NULL
-- 2  | Sam Ortiz | 1
-- 3  | Jo Kim    | 2
-- 4  | Lee Ross  | 2
-- 5  | Ana Diaz  | 1

-- In SQL Server, leave out RECURSIVE
WITH RECURSIVE chain AS (
  SELECT id, name, manager_id, 0 AS level
  FROM employees
  WHERE name = 'Jo Kim'
  UNION ALL
  SELECT e.id, e.name, e.manager_id, chain.level + 1
  FROM employees e
  JOIN chain ON e.id = chain.manager_id
)
SELECT level, name FROM chain ORDER BY level;

-- Output:
-- level | name
-- ------+----------
-- 0     | Jo Kim
-- 1     | Sam Ortiz
-- 2     | Maya Chen

CTE와 서브쿼리 더 읽어 보기

이 블로그의 글:

공식 문서:

Beekeeper Studio는 무료 오픈 소스 데이터베이스 GUI예요

지금까지 써 본 SQL 쿼리 & 에디터 도구 중 최고예요. 데이터베이스 관리에 필요한 모든 게 다 있어요. - ⭐⭐⭐⭐⭐ Mit

Beekeeper Studio는 빠르고 직관적이며 사용하기 쉬워요. 다양한 데이터베이스를 지원하고 Windows, Mac, Linux에서 모두 잘 작동해요.

Beekeeper의 Linux 버전은 100% 모든 기능을 갖추고 있어요. 대충 만든 부분도, 빠진 기능도 없어요.

Beekeeper Studio 사용자 후기

★★★★★
"Beekeeper Studio가 예전 SQL 작업 방식을 완전히 대체했어요. 빠르고 직관적이라 데이터베이스 작업이 다시 즐거워졌어요."
— Alex K., 데이터베이스 개발자
★★★★★
"여러 데이터베이스 GUI를 써 봤지만, Beekeeper는 기능과 단순함 사이의 균형이 완벽해요. 그냥 잘 돼요."
— Sarah M., 풀스택 엔지니어

SQL 작업 방식을 개선할 준비가 되셨나요?

download 무료 다운로드