메인 콘텐츠로 건너뛰기
함수는 최소* 두 가지 유형으로 나뉩니다. 일반 함수(보통 그냥 “함수”라고 함)와 집계 함수입니다. 이 둘은 완전히 다른 개념입니다. 일반 함수는 각 행에 개별적으로 적용되는 것처럼 동작합니다(즉, 각 행에서 함수의 결과는 다른 행에 좌우되지 않음). 반면 집계 함수는 여러 행의 값 집합을 누적합니다(즉, 전체 행 집합에 따라 달라짐). 이 섹션에서는 일반 함수를 설명합니다. 집계 함수에 대해서는 “Aggregate functions” 섹션을 참조하십시오.
‘arrayJoin’ 함수에 해당하는 세 번째 유형의 함수도 있습니다. 또한 테이블 함수도 별도의 범주로 볼 수 있습니다.

엄격한 타입 지정

표준 SQL과 달리 ClickHouse는 엄격한 타입 지정을 사용합니다. 즉, 타입 간 암시적 변환을 수행하지 않습니다. 각 함수는 정해진 타입 집합에서만 동작합니다. 따라서 경우에 따라 타입 변환 함수를 사용해야 합니다.

공통 부분표현식 제거

쿼리에서 동일한 AST(같은 레코드이거나 구문 분석 결과가 같은 경우)를 갖는 모든 표현식은 동일한 값을 갖는 것으로 간주됩니다. 이러한 표현식은 하나로 묶여 한 번만 실행됩니다. 동일한 서브쿼리도 같은 방식으로 제거됩니다.

결과의 타입

모든 함수는 결과로 단일 값 하나를 반환합니다(여러 값을 반환하지도 않고, 아무 값도 반환하지 않는 경우도 없습니다). 결과의 타입은 일반적으로 값이 아니라 인수의 타입에 의해서만 결정됩니다. 예외는 tupleElement 함수(a.N 연산자)와 toFixedString 함수입니다.

상수

설명을 단순하게 하기 위해 일부 함수는 특정 인수에 상수만 사용할 수 있습니다. 예를 들어 LIKE 연산자의 오른쪽 인수는 상수여야 합니다. 거의 모든 함수는 상수 인수에 대해 상수를 반환합니다. 예외는 난수를 생성하는 함수입니다. ‘now’ 함수는 실행 시점이 다른 쿼리에 대해 서로 다른 값을 반환하지만, 상수성은 단일 쿼리 내에서만 중요하므로 그 결과는 상수로 간주됩니다. 상수 표현식도 상수로 간주됩니다(예를 들어 LIKE 연산자의 오른쪽 부분은 여러 상수로 구성할 수 있습니다). 함수는 상수 인수와 비상수 인수에 대해 서로 다르게 구현될 수 있습니다(즉, 서로 다른 코드가 실행됩니다). 하지만 상수에 대한 결과와 동일한 값만 포함하는 실제 컬럼에 대한 결과는 서로 일치해야 합니다.

NULL 처리

함수는 다음과 같이 동작합니다:
  • 함수의 인수 중 하나 이상이 NULL이면 함수 결과도 NULL입니다.
  • 각 함수 설명에 개별적으로 명시된 특별한 동작이 있습니다. ClickHouse 소스 코드에서 이러한 함수는 UseDefaultImplementationForNulls=false를 가집니다.

불변성

함수는 인수의 값을 변경할 수 없으며, 변경 사항이 있다면 결과로 반환됩니다. 따라서 개별 함수의 계산 결과는 쿼리에서 함수가 작성된 순서에 영향을 받지 않습니다.

고차 함수

-> 연산자와 lambda(params, expr) 함수

고차 함수는 함수형 인수로 람다 함수만 받을 수 있습니다. 람다 함수를 고차 함수에 전달하려면 -> 연산자를 사용합니다. 화살표 왼쪽에는 형식 매개변수가 오며, 이는 임의의 ID 하나이거나 튜플에 포함된 여러 ID일 수 있습니다. 화살표 오른쪽에는 이러한 형식 매개변수와 테이블의 모든 컬럼을 사용할 수 있는 표현식이 옵니다. 예시:
x -> 2 * x
str -> str != Referer
여러 인수를 받는 람다 함수도 고차 함수에 전달할 수 있습니다. 이 경우 고차 함수에는 각 인수에 대응하는, 길이가 동일한 여러 배열이 전달됩니다. 일부 함수에서는 첫 번째 인수(람다 함수)를 생략할 수 있습니다. 이 경우에는 항등 매핑이 사용됩니다.

함수 이름만으로 사용하는 람다

전체 람다 표현식을 작성하는 대신 함수 이름을 고차 함수에 직접 전달할 수 있습니다. 함수 이름은 자동으로 이에 해당하는 람다 표현식으로 변환됩니다. 예시로, 다음 쌍은 서로 동일합니다:
SELECT arrayMap(negate, [1, 2, 3]);            -- [-1, -2, -3]
SELECT arrayMap(x -> negate(x), [1, 2, 3]);    -- [-1, -2, -3]

SELECT arrayMap(plus, [1, 2, 3], [10, 20, 30]);            -- [11, 22, 33]
SELECT arrayMap((x, y) -> plus(x, y), [1, 2, 3], [10, 20, 30]); -- [11, 22, 33]

SELECT arrayFilter(isNotNull, [1, NULL, 3, NULL, 5]);            -- [1, 3, 5]
SELECT arrayFilter(x -> isNotNull(x), [1, NULL, 3, NULL, 5]);    -- [1, 3, 5]

SELECT arrayFold(plus, [1, 2, 3, 4, 5], toUInt64(0));                      -- 15
SELECT arrayFold((acc, x) -> plus(acc, x), [1, 2, 3, 4, 5], toUInt64(0));  -- 15
이는 내장 함수, SQL UDF, 실행형 UDF, WebAssembly UDF에서 작동합니다. 모호한 경우에는 함수 이름보다 컬럼 이름과 별칭(alias) 이름이 우선합니다. 람다의 인수 개수는 내부 함수에서 결정됩니다. 예를 들어 arrayMap(plus, ...)plus가 2개의 인수를 받으므로 인수 개수 2를 사용합니다. 따라서 튜플 요소가 람다 인수로 언패킹되는 arrayMap(plus, [(1, 10), (2, 20)])와 같은 튜플 입력에도 작동합니다. 가변 인수 내부 함수(concat처럼 인수를 임의 개수만큼 받을 수 있는 함수)의 경우, 람다의 인수 개수는 배열 인수의 개수로 결정됩니다. 이는 arrayMap, arrayFilter, arrayFold와 같은 고차 함수에는 올바릅니다. 하지만 배열 외에 고정된 비배열 매개변수도 받는 고차 함수(예: arrayPartialSort(f, limit, arr))에서는 가변 인수 함수 이름만 사용하면 잘못된 인수 개수가 적용될 수 있으므로, 이 경우에는 명시적인 람다가 필요합니다. 가변 인수 내부 함수는 튜플 입력도 자동으로 언패킹하지 않습니다. 예를 들어 arrayMap(concat, [('a', 'b'), ('c', 'd')])는 단항 람다로 재작성되며, arrayMap((x, y) -> concat(x, y), [('a', 'b'), ('c', 'd')])와 동일하지 않습니다. 튜플 요소를 분해하여 가변 인수 호출에 사용하려면 명시적인 람다를 사용하십시오.

사용자 정의 함수(UDFs)

ClickHouse는 사용자 정의 함수를 지원합니다. 자세한 내용은 UDFs를 참조하십시오.
마지막 수정일 2026년 6월 10일