0Pricing
Coding Interview Prep · 강의

여러 CTE 연결하기

서로를 참조하는 이름 있는 단계의 파이프라인을 만듭니다.

여러 CTE 연결하기은(는) CoddyKit의 무료 Coding Interview Prep 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Coding Interview Prep 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Coding Interview Prep 강의에는 총 4개의 강의가 포함되어 있습니다.

CTE를 연결하는 이유

실제 면접 문제는 한 단계로 해결되는 경우가 드뭅니다. CTE를 연결하면 이름이 지정된 여러 단계의 파이프라인을 만들 수 있으며, 각 단계는 이전 단계의 출력을 변환합니다. 이는 숙련된 엔지니어가 복잡한 쿼리를 관리하기 쉬운 조각으로 나누는 방식과 같습니다.

하위 쿼리를 세 단계 깊이로 중첩하는 대신, 각 단계를 한 번만 작성하고 이름을 지정한 뒤 이후 단계에서 참조할 수 있습니다.

쉼표로 구분하는 구문

여러 CTE를 정의하려면 WITH를 한 번 작성한 다음, 이름이 지정된 각 블록을 쉼표로 구분합니다. WITH 키워드를 반복해서 작성하지 않습니다.

  • 맨 위에 WITH를 한 번 작성합니다.
  • 각 CTE 정의 사이에 쉼표를 넣습니다.
  • 마지막 주 쿼리 앞에는 쉼표를 넣지 않습니다.
WITH a AS (
    SELECT customer_id FROM orders
),
b AS (
    SELECT customer_id FROM a
)
SELECT *
FROM b;

이후의 CTE는 앞선 CTE를 참조할 수 있습니다

연결의 핵심은 다음과 같습니다. CTE는 자신보다 앞에 정의된 모든 CTE에서 읽을 수 있습니다. 이러한 앞 방향 전용 가시성을 이용하면 의존성 사슬을 만들 수 있습니다.

앞선 CTE에서는 이후의 CTE를 볼 수 없으므로 순서가 중요합니다. 원시 데이터에서 최종 형태로 이어지도록 단계를 배치하세요.

WITH filtered AS (
    SELECT *
    FROM events
    WHERE event_type = 'purchase'
),
per_user AS (
    SELECT user_id, COUNT(*) AS purchases
    FROM filtered
    GROUP BY user_id
)
SELECT *
FROM per_user;

예제로 살펴보기: 3단계 파이프라인

질문: 1,000달러를 초과해 지출한 고객들 중 평균 지출액은 얼마인가요? 이를 세 단계로 나눕니다. 고객별 총 지출액을 계산하고, 지출액이 큰 고객을 필터링한 다음, 그들의 평균을 계산합니다.

각 CTE 이름이 목적을 설명하므로 검토자는 흐름을 즉시 이해할 수 있습니다.

WITH spend AS (
    SELECT customer_id, SUM(amount) AS total
    FROM orders
    GROUP BY customer_id
),
big_spenders AS (
    SELECT customer_id, total
    FROM spend
    WHERE total > 1000
)
SELECT AVG(total) AS avg_big_spend
FROM big_spenders;

정의 순서가 중요합니다

가시성이 앞 방향으로만 적용되므로 다른 CTE에 의존하는 CTE는 해당 의존성보다 뒤에 나열해야 합니다. 아직 정의되지 않은 이름을 참조하면 데이터베이스에서 '관계가 존재하지 않음' 오류를 발생시킵니다.

좋은 습관은 CTE 목록을 위에서 아래로 읽으며, 사용된 각 이름이 그보다 앞에 이미 등장했는지 확인하는 것입니다.

여러 CTE에서 하나의 CTE 참조하기

하나의 CTE가 여러 후속 CTE에 데이터를 제공할 수 있습니다. 여기에서 연결 방식이 중첩된 하위 쿼리보다 뛰어납니다. 기본 결과를 한 번 계산한 뒤 그 결과에서 여러 갈래로 나눌 수 있기 때문입니다.

여기서는 active와 recent이 모두 base에서 읽으므로 로직을 중복하지 않습니다.

WITH base AS (
    SELECT * FROM users WHERE deleted = false
),
active AS (
    SELECT id FROM base WHERE last_login > NOW() - INTERVAL '7 days'
),
recent AS (
    SELECT id FROM base WHERE created_at > NOW() - INTERVAL '30 days'
)
SELECT (SELECT COUNT(*) FROM active) AS active_cnt,
       (SELECT COUNT(*) FROM recent) AS recent_cnt;

두 CTE를 함께 조인하기

연결된 CTE는 주 쿼리에서 자주 조인됩니다. 양쪽을 각각 계산한 다음 결합하는 방식입니다. 이렇게 하면 각 계산을 분리하고 조인은 단순하게 유지할 수 있습니다.

아래에서는 주문 수와 환불 수를 서로 독립적으로 계산한 다음 고객별로 조인합니다.

WITH orders_cte AS (
    SELECT customer_id, COUNT(*) AS orders
    FROM orders GROUP BY customer_id
),
refunds_cte AS (
    SELECT customer_id, COUNT(*) AS refunds
    FROM refunds GROUP BY customer_id
)
SELECT o.customer_id, o.orders, COALESCE(r.refunds, 0) AS refunds
FROM orders_cte o
LEFT JOIN refunds_cte r ON r.customer_id = o.customer_id;

중첩보다 높은 가독성

세 단계로 중첩된 하위 쿼리와 세 개의 CTE로 구성된 파이프라인을 비교해 보세요. 중첩된 버전에서는 독자가 안쪽부터 머릿속으로 하나씩 풀어야 합니다. CTE 버전은 실행 순서인 위에서 아래로 읽힙니다.

면접관이 CTE 방식을 높이 평가하는 이유는 실제 운영 환경에서 유지 관리하고 싶어 하는 방식이기 때문입니다. 각 단계에 이름을 지정하면 쉽게 낡지 않는 문서가 됩니다.

연결할 때 흔히 하는 실수

초보자는 주 SELECT 바로 앞, 즉 마지막 CTE 뒤에 쉼표를 추가하는 경우가 많습니다. 이 후행 쉼표는 구문 오류를 일으킵니다.

  • 쉼표는 CTE 정의 사이에만 넣습니다.
  • 마지막 닫는 괄호 뒤에는 쉼표 없이 바로 주 쿼리가 와야 합니다.

또 다른 함정은 각 CTE의 괄호 안에 완전한 SELECT가 하나씩 필요하다는 사실을 잊는 것입니다.

각 단계는 별도로 실행되나요

면접에서 다루는 미묘한 지점이 있습니다. 논리적으로는 파이프라인이 분리된 단계로 읽히지만, 최적화기는 이를 하나의 실행 계획으로 인라인화하고 결합할 수 있습니다. 대부분의 데이터베이스 엔진에서는 중간 결과를 물리화하는 비용을 반드시 지불해야 하는 것은 아닙니다.

따라서 CTE를 연결하면 성능 비용이 반드시 발생하지 않으면서도 여러분이 쿼리를 추론하기 쉬워집니다. 이러한 점을 언급하면 깊이 있는 이해를 보여 줄 수 있습니다.

파이프라인처럼 단계 이름 지정하기

좋은 단계 이름은 쿼리를 자체적으로 설명하는 코드로 바꿔 줍니다. 연산이 아니라 각 단계의 출력을 설명하는 이름을 우선 사용하세요.

  • spend와 big_spenders가 step1과 step2보다 낫습니다.
  • 독자는 CTE 이름만 보고도 전체 흐름을 추론할 수 있어야 합니다.
  • 단계 전체에서 일관된 이름을 사용하면 주 쿼리의 조인이 분명해집니다.

면접에서 단계 이름을 명확하게 지정하는 것은 유지 관리 가능한 운영 SQL을 작성한다는 신호입니다.

빠른 확인

연결된 CTE가 서로를 참조하는 방식을 얼마나 이해했는지 확인해 보세요.

복습: CTE 연결하기

파이프라인을 만드는 방법을 배웠습니다. WITH 하나와 쉼표로 구분된 CTE 정의를 사용하며, 각 단계는 앞선 단계를 읽을 수 있지만 이후 단계는 볼 수 없습니다.

  • 원시 데이터에서 최종 결과로 이어지도록 CTE 순서를 정합니다.
  • 기본 CTE를 여러 후속 단계에서 재사용합니다.
  • 주 쿼리 앞에 후행 쉼표를 넣지 않습니다.
  • CTE 연결은 성능을 반드시 저해하지 않으면서 가독성을 높여 줍니다.

다음: CTE와 하위 쿼리 및 임시 테이블 비교하기

자주 묻는 질문

“여러 CTE 연결하기” 강의는 무료인가요?

네 — “여러 CTE 연결하기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Coding Interview Prep 강의 전체를 잠금 해제할 수 있습니다. Coding Interview Prep 강의에는 총 4개의 강의가 포함되어 있습니다.

“여러 CTE 연결하기”에서 뭘 배우나요?

서로를 참조하는 이름 있는 단계의 파이프라인을 만듭니다. 브라우저에서 직접 실행하는 실습 코드로 Coding Interview Prep을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Coding Interview Prep을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Coding Interview Prep은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“여러 CTE 연결하기” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Coding Interview Prep 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Coding Interview Prep 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 첫 번째 CTE 작성하기
  2. 여러 CTE 연결하기
  3. CTE, 하위 쿼리와 임시 표 비교하기
  4. 중첩 쿼리를 CTE로 리팩터링하기
← Coding Interview Prep(으)로 돌아가기