메인 콘텐츠로 건너뛰기
ClickHouse는 공통 테이블 표현식(CTE), 공통 스칼라 표현식 및 재귀 쿼리를 지원합니다.

공통 테이블 표현식

공통 테이블 표현식은 이름이 있는 서브쿼리를 의미합니다. 테이블 표현식이 허용되는 SELECT 쿼리라면 어느 위치에서든 이름으로 참조할 수 있습니다. 이름이 있는 서브쿼리는 현재 쿼리의 범위 내에서, 또는 하위 서브쿼리의 범위 내에서 이름으로 참조할 수 있습니다. SELECT 쿼리에서 공통 테이블 표현식에 대한 모든 참조는 CTE가 명시적으로 구체화된 것으로 정의되지 않은 한(Materialized Common Table Expressions 참조), 항상 해당 정의의 서브쿼리로 대체됩니다. 재귀는 현재 CTE를 식별자 해석 과정에서 숨겨 방지합니다. CTE는 호출되는 모든 위치에서 동일한 결과를 보장하지 않는다는 점에 유의하십시오. 사용될 때마다 쿼리가 다시 실행되기 때문입니다.

구문

예시

서브쿼리가 다시 실행되는 경우의 예시는 다음과 같습니다:
CTE가 단순한 코드 조각이 아니라 결과 자체를 그대로 전달한다면, 항상 1000000이 표시됩니다. 하지만 cte_numbers를 두 번 참조하기 때문에 매번 난수가 생성되고, 그 결과 280501, 392454, 261636, 196227 등 서로 다른 값이 표시됩니다…

구체화된 공통 테이블 표현식

기본적으로 ClickHouse는 CTE의 서브쿼리를 참조되는 각 지점에 인라인하므로, 참조될 때마다 다시 실행합니다. MATERIALIZED 키워드를 추가하면 ClickHouse는 CTE 서브쿼리를 정확히 한 번만 실행하고, 그 결과를 임시 테이블에 저장한 다음, 모든 참조가 해당 테이블에서 결과를 가져오도록 합니다. 따라서 동일한 CTE가 하나의 쿼리에서 여러 번 참조되는 경우(예: self-join 또는 여러 IN 서브쿼리) 특히 유용합니다. 기본 계산은 한 번만 수행되기 때문입니다.
구체화된 CTE는 실험적 기능입니다. 사용하려면 분석기와 설정 enable_materialized_cte가 활성화되어 있어야 합니다.

구문

사용하면 좋은 경우

구체화된 CTE는 다음과 같은 경우에 특히 유용합니다.
  • 하나의 쿼리에서 동일한 CTE를 두 번 이상 참조하는 경우입니다. MATERIALIZED를 사용하지 않으면 각 참조마다 서브쿼리가 독립적으로 다시 실행됩니다.
  • CTE에 generateRandom과 같은 비결정적 함수가 포함된 경우입니다. 구체화하면 모든 참조에서 동일한 데이터를 보게 됩니다.
  • CTE에 비용이 큰 계산(집계, 조인, 대규모 스캔)이 포함되어 있어 반복 실행을 피해야 하는 경우입니다.
구체화된 CTE가 한 번만 참조되면 ClickHouse는 불필요한 오버헤드를 피하기 위해 이를 자동으로 일반 서브쿼리에 인라인합니다.

예시

예시 1: 구체화된 CTE에 대한 셀프 조인 MATERIALIZED가 없으면 조인의 양쪽에서 각각 서브쿼리를 독립적으로 실행합니다. MATERIALIZED를 사용하면 테이블을 한 번만 스캔하고, 조인의 양쪽이 동일한 임시 테이블에서 읽습니다.
예시 2: 비결정적 함수로 결정적인 결과 얻기 일반 CTE에서 generateRandom을 사용하면 참조할 때마다 서로 다른 결과가 생성됩니다. CTE를 구체화하면 일관성이 보장됩니다:
두 참조 모두 동일한 구체화된 데이터에서 읽으므로 결과는 항상 1000000입니다. 예시 3: 구체화된 CTE 연결하기 구체화된 CTE는 다른 구체화된 CTE를 참조할 수 있습니다. ClickHouse는 종속성을 해결하고 올바른 순서로 구체화합니다.
CTE 정의 순서는 중요하지 않습니다 — 전방 참조가 허용됩니다:

제약 사항

  • 실험적 설정 필요: enable_materialized_cte 설정을 활성화해야 합니다.
  • 분석기 필요: 구체화된 CTE는 분석기가 활성화된 경우에만 작동합니다(enable_analyzer = 1).
  • RECURSIVE와 함께 사용할 수 없음: MATERIALIZEDRECURSIVE 키워드를 함께 사용하는 것은 허용되지 않으며, UNSUPPORTED_METHOD 예외가 발생합니다.
  • 상관 CTE 사용 금지: 구체화된 CTE는 외부 쿼리 범위의 컬럼을 참조할 수 없습니다.

공통 스칼라 표현식

ClickHouse에서는 WITH 절에서 임의의 스칼라 표현식에 대한 별칭을 선언할 수 있습니다. 공통 스칼라 표현식은 쿼리의 어느 위치에서나 참조할 수 있습니다.
공통 스칼라 표현식이 상수 리터럴이 아닌 다른 대상을 참조하면 해당 표현식으로 인해 자유 변수가 생길 수 있습니다. ClickHouse는 식별자를 가능한 한 가장 가까운 범위에서 해석하므로, 이름 충돌이 발생하면 자유 변수가 예상치 못한 개체를 참조하거나 상관 서브쿼리로 이어질 수 있습니다. 표현식 식별자 해석이 더 예측 가능하게 동작하도록, 사용된 모든 식별자를 바인딩하는 람다 함수로 CSE를 정의하는 것이 좋습니다(분석기가 활성화된 경우에만 가능).

구문

예시

예시 1: 상수 표현식을 “변수”처럼 사용하기
예시 2: 고차 함수를 사용해 식별자의 범위를 한정하기
예시 3: 자유 변수를 사용하는 고차 함수 다음 예시 쿼리는 바인딩되지 않은 식별자가 가장 가까운 스코프의 엔터티로 해석됨을 보여줍니다. 여기서 extensiongen_name 람다 함수 본문에서 바인딩되어 있지 않습니다. extensiongenerated_names의 정의 및 사용 스코프에서 공통 스칼라 표현식으로 '.txt'로 정의되어 있지만, generated_names 서브쿼리(subquery)에서 사용할 수 있으므로 테이블 extension_list의 컬럼(column)으로 해석됩니다.
예시 4: SELECT 절의 컬럼 목록에서 sum(bytes) 표현식 결과 제거하기
예시 5: 스칼라 서브쿼리 결과 사용하기
예시 6: 서브쿼리에서 표현식 재사용

재귀 쿼리

선택적 RECURSIVE 수정자를 사용하면 WITH 쿼리가 자신의 출력 결과를 참조할 수 있습니다. 예시: 예시: 1부터 100까지 정수의 합
재귀 CTE는 버전 **24.3**에 도입된 쿼리 분석기에 의존합니다. 24.3+ 버전을 사용 중인데 (UNKNOWN_TABLE) 또는 (UNSUPPORTED_METHOD) 예외가 발생한다면, 인스턴스, role 또는 profile에서 분석기가 비활성화되어 있음을 의미합니다. 분석기를 활성화하려면 allow_experimental_analyzer 설정을 켜거나 compatibility 설정을 더 최신 버전으로 업데이트하십시오. 24.8 버전부터 분석기는 완전히 정식 기능으로 승격되었으며, allow_experimental_analyzer 설정 이름은 enable_analyzer로 변경되었습니다.
재귀 WITH 쿼리의 일반적인 형태는 항상 비재귀 항, 그다음 UNION ALL, 그다음 재귀 항으로 이루어집니다. 이때 쿼리 자신의 출력에 대한 참조를 포함할 수 있는 것은 재귀 항뿐입니다. 재귀 CTE 쿼리는 다음과 같이 실행됩니다:
  1. 비재귀 항을 평가합니다. 비재귀 항 쿼리의 결과를 임시 작업 테이블에 저장합니다.
  2. 작업 테이블이 비어 있지 않은 동안 다음 단계를 반복합니다:
    1. 재귀 항을 평가하면서, 재귀 자기 참조를 작업 테이블의 현재 내용으로 치환합니다. 재귀 항 쿼리의 결과를 임시 중간 테이블에 저장합니다.
    2. 작업 테이블의 내용을 중간 테이블의 내용으로 대체한 다음, 중간 테이블을 비웁니다.
재귀 쿼리는 일반적으로 계층형 데이터나 트리 구조 데이터를 다룰 때 사용됩니다. 예를 들어, 트리 순회를 수행하는 쿼리를 작성할 수 있습니다: 예시: 트리 순회 먼저 트리 테이블을 생성해 보겠습니다:
다음 쿼리로 해당 트리를 순회할 수 있습니다: 예시: 트리 순회

탐색 순서

깊이 우선 순서를 만들기 위해 각 결과 행마다 지금까지 방문한 행의 배열을 계산합니다: 예시: 트리 순회의 깊이 우선 순서
너비 우선 순서를 만들기 위한 표준적인 방법은 검색 깊이를 추적하는 컬럼을 추가하는 것입니다: 예시: 트리 순회 너비 우선 순서

사이클 감지

먼저 그래프 테이블을 만들어 보겠습니다:
다음 쿼리로 해당 그래프를 순회할 수 있습니다: 예시: 사이클 감지 없이 그래프 순회
하지만 해당 그래프에 사이클이 추가되면 앞선 쿼리는 Maximum recursive CTE evaluation depth 오류로 실패합니다:
사이클을 처리하는 일반적인 방법은 이미 방문한 노드들의 배열을 구하는 것입니다: 예시: 사이클 감지를 포함한 그래프 순회

무한 쿼리

외부 쿼리에서 LIMIT를 사용하면 무한 재귀 CTE 쿼리도 사용할 수 있습니다: 예시: 무한 재귀 CTE 쿼리

후행 쉼표

WITH 절의 마지막 요소 뒤에도 쉼표를 사용할 수 있습니다:
마지막 수정일 2026년 7월 2일