메인 콘텐츠로 건너뛰기

개요

조건식 결과 직접 사용하기

조건식은 항상 0, 1 또는 NULL로 평가됩니다. 따라서 다음과 같이 조건식의 결과를 직접 사용할 수 있습니다.
SELECT left < right AS is_small
FROM LEFT_RIGHT

┌─is_small─┐
│     ᴺᵁᴸᴸ │
1
0
0
│     ᴺᵁᴸᴸ │
└──────────┘

조건식의 NULL 값

조건식에 NULL 값이 포함되면 결과 역시 NULL이 됩니다.
SELECT
    NULL < 1,
    2 < NULL,
    NULL < NULL,
    NULL = NULL

┌─less(NULL, 1)─┬─less(2, NULL)─┬─less(NULL, NULL)─┬─equals(NULL, NULL)─┐
│ ᴺᵁᴸᴸ          │ ᴺᵁᴸᴸ          │ ᴺᵁᴸᴸ             │ ᴺᵁᴸᴸ               │
└───────────────┴───────────────┴──────────────────┴────────────────────┘
따라서 타입이 Nullable이면 쿼리를 신중하게 작성해야 합니다. 다음 예시는 multiIf에 등호 조건을 추가하지 않았을 때 실패하는 모습을 보여줍니다.
SELECT
    left,
    right,
    multiIf(left < right, 'left is smaller', left > right, 'right is smaller', 'Both equal') AS faulty_result
FROM LEFT_RIGHT

┌─left─┬─right─┬─faulty_result────┐
│ ᴺᵁᴸᴸ │     4Both equal       │
13 │ left is smaller  │
22Both equal       │
31 │ right is smaller │
4 │  ᴺᵁᴸᴸ │ Both equal       │
└──────┴───────┴──────────────────┘

CASE 문

ClickHouse의 CASE 표현식은 SQL CASE 연산자와 유사한 조건부 로직을 제공합니다. 조건을 평가한 뒤, 가장 먼저 일치하는 조건에 따라 값을 반환합니다. ClickHouse는 CASE를 두 가지 형태로 지원합니다.
  1. CASE WHEN ... THEN ... ELSE ... END
    이 형태는 매우 유연하며, 내부적으로 multiIf 함수를 사용해 구현됩니다. 각 조건은 서로 독립적으로 평가되며, 표현식에는 상수가 아닌 값도 포함할 수 있습니다.
SELECT
    number,
    CASE
        WHEN number % 2 = 0 THEN number + 1
        WHEN number % 2 = 1 THEN number * 10
        ELSE number
    END AS result
FROM system.numbers
WHERE number < 5;

-- 다음으로 변환됩니다
SELECT
    number,
    multiIf((number % 2) = 0, number + 1, (number % 2) = 1, number * 10, number) AS result
FROM system.numbers
WHERE number < 5

┌─number─┬─result─┐
01
110
23
330
45
└────────┴────────┘

5 rows in set. Elapsed: 0.002 sec.
  1. CASE <expr> WHEN <val1> THEN ... WHEN <val2> THEN ... ELSE ... END
    이 더 간결한 형식은 상수 값 매칭에 최적화되어 있으며, 내부적으로 caseWithExpression()을 사용합니다.
예시로, 다음 구문은 유효합니다:
SELECT
    number,
    CASE number
        WHEN 0 THEN 100
        WHEN 1 THEN 200
        ELSE 0
    END AS result
FROM system.numbers
WHERE number < 3;

-- 다음으로 변환됩니다

SELECT
    number,
    caseWithExpression(number, 0, 100, 1, 200, 0) AS result
FROM system.numbers
WHERE number < 3

┌─number─┬─result─┐
0100
1200
20
└────────┴────────┘

3 rows in set. Elapsed: 0.002 sec.
이 형식에서는 반환 표현식이 반드시 상수일 필요도 없습니다.
SELECT
    number,
    CASE number
        WHEN 0 THEN number + 1
        WHEN 1 THEN number * 10
        ELSE number
    END
FROM system.numbers
WHERE number < 3;

-- 다음으로 변환됩니다

SELECT
    number,
    caseWithExpression(number, 0, number + 1, 1, number * 10, number)
FROM system.numbers
WHERE number < 3

┌─number─┬─caseWithExpr⋯0), number)─┐
01
110
22
└────────┴──────────────────────────┘

3 rows in set. Elapsed: 0.001 sec.

주의 사항

ClickHouse는 조건을 평가하기 전에 CASE 표현식(또는 multiIf와 같은 내부적으로 동등한 표현)의 결과 타입을 결정합니다. 이는 반환 표현식의 타입이 서로 다를 때, 예를 들어 시간대나 숫자 타입이 다를 때 중요합니다.
  • 결과 타입은 모든 브랜치 중에서 가장 크게 호환되는 타입을 기준으로 선택됩니다.
  • 이 타입이 한 번 선택되면, 다른 모든 브랜치는 암묵적으로 해당 타입으로 CAST됩니다. 해당 로직이 런타임에 실제로 실행되지 않더라도 마찬가지입니다.
  • DateTime64처럼 시간대가 타입 시그니처의 일부인 타입에서는 예상치 못한 동작이 발생할 수 있습니다. 즉, 다른 브랜치에서 서로 다른 시간대를 지정하더라도 처음 발견된 시간대가 모든 브랜치에 사용될 수 있습니다.
예를 들어, 아래에서는 모든 행이 처음으로 일치한 브랜치의 시간대, 즉 Asia/Kolkata 기준의 타임스탬프를 반환합니다.
SELECT
    number,
    CASE
        WHEN number = 0 THEN fromUnixTimestamp64Milli(0, 'Asia/Kolkata')
        WHEN number = 1 THEN fromUnixTimestamp64Milli(0, 'America/Los_Angeles')
        ELSE fromUnixTimestamp64Milli(0, 'UTC')
    END AS tz
FROM system.numbers
WHERE number < 3;

-- 다음으로 변환됩니다

SELECT
    number,
    multiIf(number = 0, fromUnixTimestamp64Milli(0, 'Asia/Kolkata'), number = 1, fromUnixTimestamp64Milli(0, 'America/Los_Angeles'), fromUnixTimestamp64Milli(0, 'UTC')) AS tz
FROM system.numbers
WHERE number < 3

┌─number─┬──────────────────────tz─┐
01970-01-01 05:30:00.000
11970-01-01 05:30:00.000
21970-01-01 05:30:00.000
└────────┴─────────────────────────┘

3 rows in set. Elapsed: 0.011 sec.
여기서 ClickHouse는 여러 DateTime64(3, <timezone>) 반환 타입을 확인합니다. 처음 확인한 DateTime64(3, 'Asia/Kolkata'를 공통 타입으로 추론하고, 다른 브랜치는 이 타입으로 암묵적으로 변환합니다. 이 문제는 의도한 시간대 포맷을 유지할 수 있도록 문자열로 변환하여 해결할 수 있습니다:
SELECT
    number,
    multiIf(
        number = 0, formatDateTime(fromUnixTimestamp64Milli(0), '%F %T', 'Asia/Kolkata'),
        number = 1, formatDateTime(fromUnixTimestamp64Milli(0), '%F %T', 'America/Los_Angeles'),
        formatDateTime(fromUnixTimestamp64Milli(0), '%F %T', 'UTC')
    ) AS tz
FROM system.numbers
WHERE number < 3;

-- 다음과 같이 변환됩니다

SELECT
    number,
    multiIf(number = 0, formatDateTime(fromUnixTimestamp64Milli(0), '%F %T', 'Asia/Kolkata'), number = 1, formatDateTime(fromUnixTimestamp64Milli(0), '%F %T', 'America/Los_Angeles'), formatDateTime(fromUnixTimestamp64Milli(0), '%F %T', 'UTC')) AS tz
FROM system.numbers
WHERE number < 3

┌─number─┬─tz──────────────────┐
01970-01-01 05:30:00
11969-12-31 16:00:00
21970-01-01 00:00:00
└────────┴─────────────────────┘

3 rows in set. Elapsed: 0.002 sec.

clamp

도입 버전: v24.5.0 값을 지정된 최소값과 최대값 범위로 제한합니다. 값이 최소값보다 작으면 최소값을 반환합니다. 값이 최대값보다 크면 최대값을 반환합니다. 그 외에는 값 자체를 반환합니다. 모든 인수는 서로 비교 가능한 타입이어야 합니다. 결과 타입은 모든 인수 가운데 가장 큰 호환 타입입니다. 구문
clamp(value, min, max)
인수
  • value — 범위를 제한할 값입니다. - min — 최솟값입니다. - max — 최댓값입니다.
반환 값 값을 [min, max] 범위로 제한하여 반환합니다. 예시 기본 사용법
Query
SELECT clamp(5, 1, 10) AS result;
Response
┌─result─┐
│      5 │
└────────┘
값이 최소값 미만입니다
Query
SELECT clamp(-3, 0, 7) AS result;
Response
┌─result─┐
│      0 │
└────────┘
최대값을 초과하는 값
Query
SELECT clamp(15, 0, 7) AS result;
Response
┌─result─┐
│      7 │
└────────┘

greatest

도입 버전: v1.1.0 인수 중 가장 큰 값을 반환합니다. NULL 인수는 무시됩니다.
  • 배열의 경우, 사전식으로 가장 큰 배열을 반환합니다.
  • DateTime 타입의 경우, 결과 타입은 가장 큰 타입으로 승격됩니다(예: DateTime32와 섞여 있으면 DateTime64).
NULL 동작을 변경하려면 setting least_greatest_legacy_null_behavior를 사용하세요버전 24.12에서는 하위 호환되지 않는 변경이 도입되어, 이제 NULL 값은 무시됩니다. 이전에는 인수 중 하나가 NULL이면 NULL을 반환했습니다. 이전 동작을 유지하려면 setting least_greatest_legacy_null_behavior(기본값: false)를 true로 설정하세요.
구문
greatest(x1[, x2, ...])
인수
  • x1[, x2, ...] — 비교할 하나 이상의 값입니다. 모든 인수는 서로 비교 가능한 타입이어야 합니다. Any
반환 값 인수 중 가장 큰 값을 반환하며, 호환되는 가장 큰 타입으로 승격됩니다. Any 예시 숫자 타입
Query
SELECT greatest(1, 2, toUInt8(3), 3.) AS result, toTypeName(result) AS type;
-- 비교를 위해 UInt8을 64비트로 승격해야 하므로 반환 유형은 Float64입니다.
Response
┌─result─┬─type────┐
│      3 │ Float64 │
└────────┴─────────┘
배열
Query
SELECT greatest(['hello'], ['there'], ['world']);
Response
┌─greatest(['hello'], ['there'], ['world'])─┐
│ ['world']                                 │
└───────────────────────────────────────────┘
DateTime 타입
Query
SELECT greatest(toDateTime32(now() + toIntervalDay(1)), toDateTime64(now(), 3));
-- 반환되는 유형은 DateTime64입니다. 비교를 위해 DateTime32가 64비트로 승격되어야 하기 때문입니다.
Response
┌─greatest(toD⋯(now(), 3))─┐
│  2025-05-28 15:50:53.000 │
└──────────────────────────┘

if

도입 버전: v1.1.0 조건부 분기를 수행합니다.
  • 조건 cond가 0이 아닌 값으로 평가되면 함수는 then 표현식의 결과를 반환합니다.
  • cond가 0 또는 NULL로 평가되면 else 표현식의 결과를 반환합니다.
short_circuit_function_evaluation 설정은 단락 평가를 사용할지 여부를 제어합니다. 이 기능이 활성화되면 then 표현식은 cond가 true인 행에서만 평가되고, else 표현식은 cond가 false인 행에서만 평가됩니다. 예를 들어, 단락 평가를 사용하면 다음 쿼리를 실행할 때 0으로 나누기 예외가 발생하지 않습니다.
SELECT if(number = 0, 0, intDiv(42, number)) FROM numbers(10)
thenelse는 서로 비슷한 유형이어야 합니다. 구문
if(cond, then, else)
인수
  • cond — 평가할 조건입니다. UInt8 또는 Nullable(UInt8) 또는 NULL
  • thencond가 true인 경우 반환되는 표현식입니다. - elsecond가 false 또는 NULL인 경우 반환되는 표현식입니다.
반환 값 조건 cond에 따라 then 또는 else 표현식의 결과를 반환합니다. 예시 사용 예시
Query
SELECT if(1, 2 + 2, 2 + 6) AS res;
Response
┌─res─┐
│   4 │
└─────┘

least

도입 버전: v1.1.0 인수 중 가장 작은 값을 반환합니다. NULL 인수는 무시됩니다.
  • 배열의 경우 사전식 순서로 가장 작은 배열을 반환합니다.
  • DateTime 타입의 경우 결과 타입은 가장 큰 타입으로 승격됩니다(예: DateTime32와 함께 사용되면 DateTime64).
NULL 동작을 변경하려면 설정 least_greatest_legacy_null_behavior를 사용하세요버전 24.12에서는 하위 호환되지 않는 변경이 도입되어, 이제 NULL 값은 무시됩니다. 이전에는 인수 중 하나가 NULL이면 NULL을 반환했습니다. 이전 동작을 유지하려면 설정 least_greatest_legacy_null_behavior(기본값: false)를 true로 설정하세요.
구문
least(x1[, x2, ...])
인수
  • x1[, x2, ...] — 비교할 단일 값 또는 여러 값입니다. 모든 인수는 서로 비교 가능한 타입이어야 합니다. Any
반환 값 인수 중 가장 작은 값을 반환합니다. 반환 타입은 호환 가능한 가장 큰 타입으로 승격됩니다. Any 예시 숫자형 타입
Query
SELECT least(1, 2, toUInt8(3), 3.) AS result, toTypeName(result) AS type;
-- 비교를 위해 UInt8을 64비트로 승격해야 하므로 반환 유형은 Float64입니다.
Response
┌─result─┬─type────┐
│      1 │ Float64 │
└────────┴─────────┘
배열
Query
SELECT least(['hello'], ['there'], ['world']);
Response
┌─least(['hell⋯ ['world'])─┐
│ ['hello']                │
└──────────────────────────┘
DateTime 타입
Query
SELECT least(toDateTime32(now() + toIntervalDay(1)), toDateTime64(now(), 3));
-- 반환되는 유형은 DateTime64입니다. 비교를 위해 DateTime32가 64비트로 승격되어야 하기 때문입니다.
Response
┌─least(toDate⋯(now(), 3))─┐
│  2025-05-27 15:55:20.000 │
└──────────────────────────┘

multiIf

도입 버전: v1.1.0 쿼리에서 CASE 연산자를 더 간결하게 작성할 수 있습니다. 각 조건을 순서대로 평가합니다. 처음으로 true(0이 아니고 NULL이 아닌 값)인 조건에 대해 해당 브랜치 값을 반환합니다. 어떤 조건도 true가 아니면 else 값을 반환합니다. 설정 short_circuit_function_evaluation은 단락 평가 사용 여부를 제어합니다. 이 설정이 활성화되면 then_i 표현식은 ((NOT cond_1) AND ... AND (NOT cond_{i-1}) AND cond_i)가 true인 행에서만 평가됩니다. 예를 들어, 단락 평가를 사용하면 다음 쿼리를 실행할 때 0으로 나누기 예외가 발생하지 않습니다:
SELECT multiIf(number = 2, intDiv(1, number), number = 5) FROM numbers(10)
모든 브랜치 및 else 표현식은 공통 슈퍼타입을 가져야 합니다. NULL 조건은 false로 간주됩니다. 구문
multiIf(cond_1, then_1, cond_2, then_2, ..., else)
별칭: caseWithoutExpression, caseWithoutExpr 인수
  • cond_Nthen_N을 반환할지 결정하는 N번째 평가 조건입니다. UInt8 또는 Nullable(UInt8) 또는 NULL
  • then_Ncond_N가 true일 때 함수가 반환하는 결과입니다. - else — 어떤 조건도 true가 아닐 때 함수가 반환하는 결과입니다.
반환 값 일치하는 cond_N에 대해서는 then_N의 결과를 반환하고, 그렇지 않으면 else 결과를 반환합니다. 예시 사용 예시
Query
CREATE TABLE LEFT_RIGHT (left Nullable(UInt8), right Nullable(UInt8)) ENGINE = Memory;
INSERT INTO LEFT_RIGHT VALUES (NULL, 4), (1, 3), (2, 2), (3, 1), (4, NULL);

SELECT
    left,
    right,
    multiIf(left < right, 'left is smaller', left > right, 'left is greater', left = right, 'Both equal', 'Null value') AS result
FROM LEFT_RIGHT;
Response
┌─left─┬─right─┬─result──────────┐
│ ᴺᵁᴸᴸ │     4 │ Null value      │
│    1 │     3 │ left is smaller │
│    2 │     2 │ Both equal      │
│    3 │     1 │ left is greater │
│    4 │  ᴺᵁᴸᴸ │ Null value      │
└──────┴───────┴─────────────────┘
마지막 수정일 2026년 6월 10일