메인 콘텐츠로 건너뛰기
이 섹션에서는 ClickHouse의 SQL 구문을 살펴봅니다. ClickHouse는 SQL 기반 구문을 사용하지만, 다양한 확장 기능과 최적화도 제공합니다.

쿼리 파싱

ClickHouse에는 두 가지 종류의 파서가 있습니다:
  • 전체 SQL 파서 (재귀 하강 파서)
  • 데이터 포맷 파서 (빠른 스트림 파서)
전체 SQL 파서는 INSERT 쿼리를 제외한 모든 경우에 사용되며, INSERT 쿼리에서는 두 파서가 모두 사용됩니다. 아래 쿼리를 살펴보겠습니다:
INSERT INTO t VALUES (1, 'Hello, world'), (2, 'abc'), (3, 'def')
앞서 언급했듯이 INSERT 쿼리는 두 파서를 모두 사용합니다. INSERT INTO t VALUES 구문은 전체 파서가 파싱하고, 데이터 (1, 'Hello, world'), (2, 'abc'), (3, 'def') 는 데이터 포맷 파서 또는 빠른 스트림 파서가 파싱합니다.
input_format_values_interpret_expressions 설정을 사용하면 데이터에도 전체 파서를 적용할 수 있습니다.앞서 언급한 설정을 1로 지정하면 ClickHouse는 먼저 빠른 스트림 파서로 값을 파싱하려고 시도합니다. 이 시도가 실패하면 ClickHouse는 데이터를 SQL 표현식으로 간주하고 전체 파서로 파싱을 시도합니다.
데이터는 어떤 포맷이든 사용할 수 있습니다. 쿼리를 수신하면 서버는 요청 중 max_query_size바이트를 넘지 않는 부분만 RAM에서 처리하고 (기본값은 1 MB), 나머지는 스트림 파싱합니다. 이는 대용량 INSERT 쿼리에서 발생할 수 있는 문제를 방지하기 위한 것으로, ClickHouse에 데이터를 삽입할 때 권장되는 방식입니다. INSERT 쿼리에서 Values 포맷을 사용하면 데이터가 SELECT 쿼리의 표현식과 동일한 방식으로 파싱되는 것처럼 보일 수 있지만, 실제로는 그렇지 않습니다. Values 포맷은 훨씬 더 제한적입니다. 이 섹션의 나머지 부분에서는 전체 파서를 설명합니다.
포맷 파서에 관한 자세한 내용은 포맷 섹션을 참조하십시오.

공백

  • 구문 요소 사이에는(쿼리의 시작과 끝을 포함) 공백 문자가 몇 개든 올 수 있습니다.
  • 공백 문자에는 space, tab, line feed, CR, form feed가 포함됩니다.

주석

ClickHouse는 SQL 스타일 주석과 C 스타일 주석을 모두 지원합니다.
  • SQL 스타일 주석은 --, #! 또는 # 로 시작하며 줄 끝까지 계속됩니다. --#! 뒤의 공백은 생략할 수 있습니다.
  • C 스타일 주석:
    • //(또는 /가 2개를 초과해 연속된 경우) 뒤에 텍스트가 오며 줄 끝까지 계속됩니다. / 뒤에는 공백이 없어도 됩니다.
    • 여러 줄 주석은 /*부터 */까지 사용할 수 있습니다. 이 경우에도 공백은 필요하지 않습니다.
    • C 스타일 주석은 중첩할 수 있습니다.
예시는 다음과 같습니다.
/*
 * 두 날짜 사이의 일수를 계산합니다.
 * /* 인수 중 하나라도 NULL이면 NULL을 반환합니다 */
 */
SELECT
    dateDiff('day', toDate('2024-01-01'), toDate('2024-12-31')) AS days_in_year, -- 365
    dateDiff('day', toDate('2020-01-01'), today()) AS days_since  #! since 2020
    ///////////////////////////////////////////////////////////////////
    # TODO: 시간/분 단위 변형 추가

키워드

ClickHouse의 키워드는 문맥에 따라 대소문자를 구분할 수도 있고 구분하지 않을 수도 있습니다. 키워드는 다음에 해당할 때 대소문자를 구분하지 않습니다:
  • SQL 표준. 예를 들어 SELECT, select, SeLeCt는 모두 유효합니다.
  • 널리 사용되는 일부 DBMS(MySQL 또는 Postgres)의 구현. 예를 들어 DateTimedatetime은 동일합니다.
system.data_type_families 테이블에서 데이터 타입 이름이 대소문자를 구분하는지 확인할 수 있습니다.
반면 표준 SQL과 달리, 그 밖의 모든 키워드(함수 이름 포함)는 대소문자를 구분합니다. 또한 키워드는 예약어가 아닙니다. 해당 문맥에서만 키워드로 처리됩니다. 키워드와 같은 이름의 식별자를 사용하는 경우 큰따옴표나 백틱으로 감싸십시오. 예를 들어 table_name 테이블에 "FROM"이라는 이름의 컬럼이 있으면, 다음 쿼리는 유효합니다:
SELECT "FROM" FROM table_name

식별자

식별자에는 다음이 포함됩니다. 식별자는 따옴표로 묶거나 묶지 않고 사용할 수 있지만, 따옴표로 묶지 않는 방식이 권장됩니다. 따옴표로 묶지 않은 식별자는 정규식 ^[a-zA-Z_][0-9a-zA-Z_]*$와 일치해야 하며, 키워드와 같을 수 없습니다. 유효한 식별자와 유효하지 않은 식별자의 예시는 아래 표를 참조하십시오.
유효한 식별자유효하지 않은 식별자
xyz, _internal, Id_with_underscores_123_1x, tom@gmail.com, äußerst_schön
키워드와 동일한 식별자를 사용하거나 식별자에 다른 기호를 사용하려면 "id", `id`처럼 큰따옴표 또는 backticks로 묶으십시오.
따옴표로 묶은 식별자에 적용되는 이스케이프 규칙은 문자열 리터럴에도 동일하게 적용됩니다. 자세한 내용은 String을 참조하십시오.
컬럼 이름에 점을 사용하지 마십시오점이 포함된 컬럼 이름, 동일한 점 접두사를 공유하는 컬럼, 그리고 Array 타입의 컬럼은 flatten_nested = 1(기본값)일 때 각각 평탄화된 Nested 구조의 일부로 해석될 수 있습니다. 이로 인해 삽입 시 예상치 못한 배열 길이 검증과 이름 변경 제한이 발생할 수 있습니다.가능하면 컬럼 이름에 점을 사용하지 마십시오. 의도적으로 Nested 의미 체계가 필요한 경우가 아니라면 컬럼 이름의 점 대신 밑줄(_)이나 다른 구분자를 사용하십시오.

리터럴

ClickHouse에서 리터럴은 쿼리에서 직접 표현되는 값입니다. 즉, 쿼리 실행 중에 변하지 않는 고정된 값입니다. 리터럴은 다음과 같은 유형이 있습니다: 아래 섹션에서 각각을 더 자세히 살펴보겠습니다.

String

String 리터럴은 작은따옴표로 묶어야 합니다. 큰따옴표는 지원되지 않습니다. 이스케이프는 다음 두 가지 방식으로 처리할 수 있습니다.
  • 작은따옴표 문자 ' 앞에 작은따옴표를 붙이는 방식으로, 이 경우 작은따옴표 문자만 ''로 이스케이프할 수 있습니다.
  • 앞에 백슬래시를 붙이고 아래 표에 나열된 지원되는 이스케이프 시퀀스를 사용하는 방식입니다.
백슬래시는 아래에 나열된 문자 이외의 문자 앞에 오면 특별한 의미를 잃으며, 문자 그대로 해석됩니다.
지원되는 이스케이프설명
\xHH8비트 문자 지정이며, 뒤에 임의 개수의 16진수 숫자(H)가 올 수 있습니다.
\N예약됨, 아무 동작도 하지 않습니다(예: SELECT 'a\Nb'ab를 반환합니다)
\a벨 문자
\b백스페이스
\e이스케이프 문자
\f폼 피드
\n줄 바꿈
\r캐리지 리턴
\t가로 탭
\v세로 탭
\0널 문자
\\백슬래시
\' (or '')작은따옴표
\"큰따옴표
`백틱
\/슬래시
\=등호
ASCII control characters (c <= 31).ASCII 제어 문자(c <= 31)
문자열 리터럴에서는 최소한 '\를 이스케이프 코드 \'(또는 '') 및 \\를 사용해 이스케이프해야 합니다.

숫자

숫자 리터럴은 다음과 같이 파싱됩니다.
  • 리터럴 앞에 마이너스 기호 -가 있으면 해당 토큰은 건너뛰고, 파싱이 끝난 후 결과에 음수 부호를 적용합니다.
  • 숫자 리터럴은 먼저 strtoull 함수를 사용해 64비트 부호 없는 정수로 파싱됩니다.
    • 값 앞에 0b 또는 0x/0X가 있으면 각각 2진수 또는 16진수로 파싱됩니다.
    • 값이 음수이고 절댓값이 263보다 크면 오류가 반환됩니다.
  • 이 단계가 실패하면 다음으로 strtod 함수를 사용해 부동소수점 수로 파싱됩니다.
  • 그 외의 경우에는 오류가 반환됩니다.
리터럴 값은 해당 값을 표현할 수 있는 가장 작은 타입으로 CAST됩니다. 예시:
  • 1UInt8로 파싱됩니다
  • 256UInt16로 파싱됩니다.
중요64비트를 초과하는 정수 값(UInt128, Int128, UInt256, Int256)은 올바르게 파싱하려면 더 큰 타입으로 CAST해야 합니다.
-170141183460469231731687303715884105728::Int128
340282366920938463463374607431768211455::UInt128
-57896044618658097711785492504343953926634992332820282019728792003956564819968::Int256
115792089237316195423570985008687907853269984665640564039457584007913129639935::UInt256
이렇게 하면 위 알고리즘을 우회하여 임의 정밀도를 지원하는 루틴으로 정수를 파싱합니다.그렇지 않으면 리터럴이 부동소수점 수로 파싱되어 잘림으로 인한 정밀도 손실이 발생할 수 있습니다.
자세한 내용은 데이터 타입을 참조하십시오. 숫자 리터럴 내부의 밑줄 _은 무시되며, 가독성을 높이기 위해 사용할 수 있습니다. 다음 Numeric 리터럴이 지원됩니다.
숫자 리터럴예시
정수1, 10_000_000, 18446744073709551615, 01
소수0.1
지수 표기법1e100, -1e-100
부동소수점 수123.456, inf, nan
16진수0xc0fe
SQL 표준 호환 16진 문자열x'c0fe'
2진수0b1101
SQL 표준 호환 2진 문자열b'1101'
의도치 않은 해석 오류를 방지하기 위해 8진수 리터럴은 지원되지 않습니다.

복합

배열은 []로 만듭니다: [1, 2, 3]. 튜플은 ()로 만듭니다: (1, 'Hello, world!', 2). 엄밀히 말하면 이들은 리터럴이 아니라, 각각 배열 생성 연산자와 튜플 생성 연산자를 사용하는 표현식입니다. 배열은 최소 1개의 항목으로 구성되어야 하며, 튜플은 최소 2개의 항목으로 구성되어야 합니다.
튜플이 SELECT 쿼리의 IN 절에 나타나는 경우는 별도로 다룹니다. 쿼리 결과에 튜플이 포함될 수는 있지만, 튜플은 데이터베이스에 저장할 수 없습니다(Memory 엔진을 사용하는 테이블은 예외).

NULL

NULL은 값이 없음을 나타내는 데 사용됩니다. 테이블 필드에 NULL을 저장하려면 해당 필드의 타입이 널 허용(Nullable)이어야 합니다.
NULL에 대해 다음 사항에 유의하십시오:
  • 데이터 포맷(입력 또는 출력)에 따라 NULL의 표현 방식이 다를 수 있습니다. 자세한 내용은 데이터 포맷을 참조하십시오.
  • NULL 처리는 세부적인 부분이 있습니다. 예를 들어 비교 연산의 인수 중 하나 이상이 NULL이면, 이 연산의 결과도 NULL이 됩니다. 이는 곱셈, 덧셈 및 기타 연산에도 동일하게 적용됩니다. 각 연산의 문서를 읽어 보시기 바랍니다.
  • 쿼리에서는 IS NULLIS NOT NULL 연산자와 관련 함수 isNull, isNotNull을 사용해 NULL인지 확인할 수 있습니다.

Heredoc

heredoc은 원래 포맷을 유지한 채 문자열(대개 여러 줄)을 정의하는 방법입니다. heredoc은 두 개의 $ 기호 사이에 넣는 사용자 정의 문자열 리터럴입니다. 예시:
SELECT $heredoc$SHOW CREATE VIEW my_view$heredoc$;

┌─'SHOW CREATE VIEW my_view'─┐
│ SHOW CREATE VIEW my_view   │
└────────────────────────────┘
  • 두 heredoc 사이의 값은 “있는 그대로” 처리됩니다.
  • heredoc을 사용해 SQL, HTML 또는 XML 코드 등의 스니펫을 삽입할 수 있습니다.

쿼리 매개변수 정의 및 사용

쿼리 매개변수를 사용하면 구체적인 식별자 대신 추상적인 플레이스홀더를 포함한 일반적인 쿼리를 작성할 수 있습니다. 쿼리 매개변수가 포함된 쿼리가 실행되면 모든 플레이스홀더가 해석되어 실제 쿼리 매개변수 값으로 대체됩니다. 쿼리 매개변수는 여러 가지 방법으로 정의할 수 있습니다:
  • SET param_<name>=<value> — 쿼리에서 SET 명령을 사용합니다.
  • --param_<name>='<value>' — 명령줄에서 clickhouse-client 인수로 지정합니다.
  • param_<name>=<value> — HTTP 인터페이스의 URL 쿼리 문자열 매개변수로 지정합니다.
쿼리 매개변수는 쿼리에서 {<name>: <datatype>} 형식으로 참조할 수 있습니다. 여기서 <name>은 쿼리 매개변수 이름이고 <datatype>은 변환할 데이터 타입입니다.
예를 들어, 다음 SQL은 a, b, c, d라는 이름의 매개변수를 정의하며, 각각 서로 다른 데이터 타입을 사용합니다:
SET param_a = 13;
SET param_b = 'str';
SET param_c = '2022-08-04 18:30:53';
SET param_d = {'10': [11, 12], '13': [14, 15]};

SELECT
   {a: UInt32},
   {b: String},
   {c: DateTime},
   {d: Map(String, Array(UInt8))};

13    str    2022-08-04 18:30:53    {'10':[11,12],'13':[14,15]}
clickhouse-client를 사용하는 경우 매개변수는 --param_name=value 형식으로 지정합니다. 예를 들어, 다음 매개변수는 이름이 message이며 String으로 가져옵니다:
clickhouse-client --param_message='hello' --query="SELECT {message: String}"

hello
쿼리 매개변수가 데이터베이스, 테이블, 함수 또는 기타 식별자의 이름을 나타내는 경우에는 타입으로 Identifier를 사용하십시오. 예를 들어, 다음 쿼리는 uk_price_paid라는 이름의 테이블에서 행을 반환합니다:
SET param_mytablename = "uk_price_paid";
SELECT * FROM {mytablename:Identifier};
쿼리 매개변수는 param_ 접두사가 붙은 URL 쿼리 문자열 매개변수로 전달할 수 있습니다. 예를 들면 다음과 같습니다:
curl -s "http://localhost:8123/?param_message=hello" --data-binary "SELECT {message: String}"

hello
기본 제공 Web UI(play.html)는 쿼리의 {name:Type} 매개변수 플레이스홀더를 자동으로 감지하고, 각 매개변수에 대해 레이블이 붙은 입력 필드를 표시합니다. 매개변수 값은 HTTP 요청에 포함되며, 북마크 및 공유를 위해 페이지 URL에도 저장됩니다.
쿼리 매개변수는 임의의 SQL 쿼리의 임의 위치에서 사용할 수 있는 일반적인 텍스트 치환 기능이 아닙니다. 주로 식별자 또는 리터럴 자리에 사용하는 SELECT SQL 문에서 동작하도록 설계되었습니다.

함수

함수 호출은 식별자 뒤에 인수 목록(비어 있을 수 있음)을 ()로 감싼 형태로 작성합니다. 표준 SQL과 달리, 인수 목록이 비어 있어도 괄호를 반드시 써야 합니다. 예를 들면 다음과 같습니다:
now()
다음 항목도 있습니다: 일부 집계 함수는 괄호 안에 두 개의 인수 목록이 들어갈 수 있습니다. 예시는 다음과 같습니다:
quantile (0.9)(x) 
이러한 집계 함수는 “매개변수형” 함수라고 하며, 첫 번째 목록에 있는 인수를 “매개변수”라고 합니다.
매개변수가 없는 집계 함수의 구문은 일반 함수와 같습니다.

연산자

연산자는 쿼리를 구문 분석할 때 우선순위와 결합 방향을 고려해 해당 함수로 변환됩니다. 예를 들어, 다음 표현식은
1 + 2 * 3 + 4
로 변환됩니다
plus(plus(1, multiply(2, 3)), 4)`

데이터 타입과 데이터베이스 테이블 엔진

CREATE 쿼리에서 데이터 타입과 테이블 엔진은 식별자나 함수와 동일한 방식으로 작성됩니다. 즉, 괄호 안의 인수 목록이 있을 수도 있고 없을 수도 있습니다. 자세한 내용은 다음 섹션을 참조하십시오.

표현식

표현식은 다음 중 하나일 수 있습니다:
  • 함수
  • 식별자
  • 리터럴
  • 연산자의 적용
  • 괄호로 묶인 표현식
  • 하위 쿼리(subquery)
  • 애스터리스크(*)
또한 별칭을 포함할 수도 있습니다. 표현식 목록은 쉼표로 구분된 하나 이상의 표현식으로 이루어집니다. 또한 함수와 연산자는 표현식을 인수로 사용할 수 있습니다. 상수 표현식은 쿼리 분석 단계, 즉 실행 전에 결과를 알 수 있는 표현식입니다. 예를 들어, 리터럴로 이루어진 표현식은 상수 표현식입니다.

표현식 별칭

별칭은 쿼리의 표현식에 사용자가 지정한 이름입니다.
expr AS alias
위 구문의 각 요소는 아래에서 설명합니다.
구문의 부분설명예시참고
AS별칭을 정의하는 키워드입니다. AS 키워드를 사용하지 않아도 SELECT 절에서 테이블 이름이나 컬럼 이름에 별칭을 지정할 수 있습니다.SELECT table_name_alias.column_name FROM table_name table_name_alias.CAST 함수에서는 AS 키워드가 다른 의미로 사용됩니다. 함수 설명을 참조하십시오.
exprClickHouse에서 지원하는 모든 표현식입니다.SELECT column_name * 2 AS double FROM some_table
aliasexpr에 대한 이름입니다. 별칭은 식별자 구문을 따라야 합니다.SELECT "table t".column_name FROM table_name AS "table t".

사용 시 참고 사항

  • 별칭은 쿼리 또는 하위 쿰리 전체에 전역으로 적용되며, 어떤 표현식이든 쿼리의 어느 부분에서나 별칭으로 정의할 수 있습니다. 예시는 다음과 같습니다:
SELECT (1 AS n) + 2, n`.
  • 별칭은 하위 쿼리 내부나 하위 쿼리 간에는 사용할 수 없습니다. 예를 들어, 다음 쿼리를 실행하면 ClickHouse에서 Unknown identifier: num 예외가 발생합니다:
`SELECT (SELECT sum(b.a) + num FROM b) - a.a AS num FROM a`
  • 하위 쿼리의 SELECT 절에서 결과 컬럼에 별칭이 정의되어 있으면, 해당 컬럼은 외부 쿼리에서 참조할 수 있습니다. 예시:
SELECT n + m FROM (SELECT 1 AS n, 2 AS m)`.
  • 별칭이 컬럼 또는 테이블 이름과 동일한 경우에는 주의하십시오. 다음 예시를 살펴보겠습니다:
CREATE TABLE t
(
    a Int,
    b Int
)
ENGINE = TinyLog();

SELECT
    argMax(a, b),
    sum(b) AS b
FROM t;

서버에서 예외가 수신되었습니다 (버전 18.14.17):
Code: 184. DB::Exception: Received from localhost:9000, 127.0.0.1. DB::Exception: Aggregate function sum(b) is found inside another aggregate function in query.
앞선 예시에서는 컬럼 b를 가진 테이블 t를 선언했습니다. 그런 다음 데이터를 선택할 때 sum(b) AS b alias를 정의했습니다. alias는 전역적으로 적용되므로, ClickHouse는 표현식 argMax(a, b)의 리터럴 b를 표현식 sum(b)로 대체했습니다. 이 대체로 인해 예외가 발생했습니다.
prefer_column_name_to_alias1로 설정하면 이 기본 동작을 변경할 수 있습니다.

Asterisk

SELECT 쿼리에서는 별표(*)를 사용해 표현식을 대체할 수 있습니다. 자세한 내용은 SELECT 섹션을 참고하십시오.
마지막 수정일 2026년 6월 10일