Visão geral
Usando resultados condicionais diretamente
Condicionais sempre resultam em 0, 1 ou NULL. Portanto, você pode usar esses resultados diretamente assim:
SELECT left < right AS is_small
FROM LEFT_RIGHT
┌Valores NULL em condicionais
Quando valores NULL estão envolvidos em condicionais, o resultado também será NULL.
SELECT
NULL < 1,
2 < NULL,
NULL < NULL,
NULL = NULL
┌Portanto, você deve construir suas consultas com cuidado se os tipos forem Nullable.
O exemplo a seguir demonstra isso ao não adicionar a condição de igualdade a multiIf.
SELECT
left,
right,
multiIf(left < right, 'left is smaller', left > right, 'right is smaller', 'Both equal') AS faulty_result
FROM LEFT_RIGHT
┌Instrução CASE
A expressão CASE no ClickHouse fornece uma lógica condicional semelhante ao operador CASE do SQL. Ela avalia condições e retorna valores com base na primeira condição que corresponde.
O ClickHouse oferece suporte a duas formas de CASE:
CASE WHEN ... THEN ... ELSE ... END
Esta forma oferece total flexibilidade e é implementada internamente com a função multiIf. Cada condição é avaliada de forma independente, e as expressões podem incluir valores não constantes.
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;
-- é convertido para
SELECT
number,
multiIf((number % 2) = 0, number + 1, (number % 2) = 1, number * 10, number) AS result
FROM system.numbers
WHERE number < 5
┌CASE <expr> WHEN <val1> THEN ... WHEN <val2> THEN ... ELSE ... END
Essa forma mais compacta é otimizada para correspondência com valores constantes e usa internamentecaseWithExpression().
Por exemplo, o seguinte é válido:
SELECT
number,
CASE number
WHEN 0 THEN 100
WHEN 1 THEN 200
ELSE 0
END AS result
FROM system.numbers
WHERE number < 3;
-- é traduzido para
SELECT
number,
caseWithExpression(number, 0, 100, 1, 200, 0) AS result
FROM system.numbers
WHERE number < 3
┌Essa forma também não exige expressões de retorno constantes.
SELECT
number,
CASE number
WHEN 0 THEN number + 1
WHEN 1 THEN number * 10
ELSE number
END
FROM system.numbers
WHERE number < 3;
-- é traduzido para
SELECT
number,
caseWithExpression(number, 0, number + 1, 1, number * 10, number)
FROM system.numbers
WHERE number < 3
┌Ressalvas
O ClickHouse determina o tipo de resultado de uma expressão CASE (ou seu equivalente interno, como multiIf) antes de avaliar quaisquer condições. Isso é importante quando as expressões de retorno diferem em tipo, como no caso de fusos horários ou tipos numéricos diferentes.
- O tipo de resultado é selecionado com base no maior tipo compatível entre todos os ramos.
- Depois que esse tipo é selecionado, todos os outros ramos são convertidos implicitamente para ele, mesmo que sua lógica nunca venha a ser executada em tempo de execução.
- Para tipos como DateTime64, em que o fuso horário faz parte da assinatura do tipo, isso pode levar a um comportamento inesperado: o primeiro fuso horário encontrado pode ser usado para todos os ramos, mesmo quando outros ramos especificam fusos horários diferentes.
Por exemplo, abaixo todas as linhas retornam o timestamp no fuso horário do primeiro ramo correspondente, ou seja, 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;
-- é convertido em
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
┌Aqui, o ClickHouse encontra vários tipos de retorno DateTime64(3, <timezone>). Ele infere o tipo comum como DateTime64(3, 'Asia/Kolkata' por ser o primeiro que encontra, convertendo implicitamente os outros ramos para esse tipo.
Isso pode ser resolvido convertendo para string para preservar a formatação de fuso horário desejada:
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;
-- é traduzido como
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
┌clamp
Introduzido em: v24.5.0
Restringe um valor para que permaneça dentro dos limites mínimo e máximo especificados.
Se o valor for menor que o mínimo, retorna o mínimo. Se o valor for maior que o máximo, retorna o máximo. Caso contrário, retorna o próprio valor.
Todos os argumentos devem ser de tipos comparáveis. O tipo do resultado é o maior tipo compatível entre todos os argumentos.
Sintaxe
clamp(value, min, max)Argumentos
value— O valor a ser restringido. -min— O limite mínimo. -max— O limite máximo.
Valor retornado
Retorna o valor, restrito ao intervalo [min, max].
Exemplos
Uso básico
SELECT clamp(5, 1, 10) AS result;┌─result─┐
│ 5 │
└────────┘Valor abaixo do mínimo
SELECT clamp(-3, 0, 7) AS result;┌─result─┐
│ 0 │
└────────┘Valor acima do limite máximo
SELECT clamp(15, 0, 7) AS result;┌─result─┐
│ 7 │
└────────┘greatest
Introduzido em: v1.1.0
Retorna o maior valor entre os argumentos.
Argumentos NULL são ignorados.
- Para arrays, retorna o array lexicograficamente maior.
- Para tipos
DateTime, o tipo do resultado é promovido para o maior tipo (por exemplo,DateTime64se combinado comDateTime32).
Sintaxe
greatest(x1[, x2, ...])Argumentos
x1[, x2, ...]— Um ou mais valores para comparar. Todos os argumentos devem ser de tipos comparáveis.Any
Valor retornado
Retorna o maior valor entre os argumentos, promovido para o maior tipo compatível. Any
Exemplos
Tipos numéricos
-- The type returned is a Float64 as the UInt8 must be promoted to 64 bit for the comparison.
SELECT greatest(1, 2, toUInt8(3), 3.) AS result, toTypeName(result) AS type;┌─result─┬─type────┐
│ 3 │ Float64 │
└────────┴─────────┘Arrays
SELECT greatest(['hello'], ['there'], ['world']);┌─greatest(['hello'], ['there'], ['world'])─┐
│ ['world'] │
└───────────────────────────────────────────┘Tipos de DateTime
-- The type returned is a DateTime64 as the DateTime32 must be promoted to 64 bit for the comparison.
SELECT greatest(toDateTime32('2025-01-02 12:00:00'), toDateTime64('2025-01-01 12:00:00.000', 3));┌─greatest(toDateTime32('2025-01-02 12:00:00'), toDateTime64('2025-01-01 12:00:00.000', 3))─┐
│ 2025-01-02 12:00:00.000 │
└───────────────────────────────────────────────────────────────────────────────────────────┘if
Introduzido em: v1.1.0
Executa uma ramificação condicional.
- Se a condição
condfor avaliada como um valor diferente de zero, a função retorna o resultado da expressãothen. - Se
condfor avaliada como zero ou NULL, o resultado da expressãoelseserá retornado.
A configuração short_circuit_function_evaluation controla se a avaliação de curto-circuito é usada.
Se estiver habilitada, a expressão then será avaliada apenas nas linhas em que cond for true, e a expressão else, naquelas em que cond for false.
Por exemplo, com a avaliação de curto-circuito, não é lançada nenhuma exceção de divisão por zero ao executar a seguinte consulta:
SELECT if(number = 0, 0, intDiv(42, number)) FROM numbers(10)then e else devem ser de tipos semelhantes.
Sintaxe
if(cond, then, else)Argumentos
cond— A condição avaliada.UInt8ouNullable(UInt8)ouNULLthen— A expressão retornada secondfor true. -else— A expressão retornada secondfor false ouNULL.
Valor retornado
O resultado de then ou else, dependendo da condição cond.
Exemplos
Exemplo de uso
SELECT if(1, 2 + 2, 2 + 6) AS res;┌─res─┐
│ 4 │
└─────┘least
Introduzido em: v1.1.0
Retorna o menor valor entre os argumentos.
Argumentos NULL são ignorados.
- Para arrays, retorna o array lexicograficamente menor.
- Para tipos DateTime, o tipo do resultado é promovido para o maior tipo (por exemplo, DateTime64 se combinado com DateTime32).
Sintaxe
least(x1[, x2, ...])Argumentos
x1[, x2, ...]— Um único valor ou vários valores a serem comparados. Todos os argumentos devem ser de tipos comparáveis.Any
Valor retornado
Retorna o menor valor entre os argumentos, promovido para o maior tipo compatível. Any
Exemplos
Tipos numéricos
-- The type returned is a Float64 as the UInt8 must be promoted to 64 bit for the comparison.
SELECT least(1, 2, toUInt8(3), 3.) AS result, toTypeName(result) AS type;┌─result─┬─type────┐
│ 1 │ Float64 │
└────────┴─────────┘Arrays
SELECT least(['hello'], ['there'], ['world']);┌─least(['hello'], ['there'], ['world'])─┐
│ ['hello'] │
└────────────────────────────────────────┘Tipos de DateTime
-- The type returned is a DateTime64 as the DateTime32 must be promoted to 64 bit for the comparison.
SELECT least(toDateTime32('2025-01-02 12:00:00'), toDateTime64('2025-01-01 12:00:00.000', 3));┌─least(toDateTime32('2025-01-02 12:00:00'), toDateTime64('2025-01-01 12:00:00.000', 3))─┐
│ 2025-01-01 12:00:00.000 │
└────────────────────────────────────────────────────────────────────────────────────────┘multiIf
Introduzido em: v1.1.0
Permite escrever o operador CASE de forma mais compacta na consulta.
Avalia cada condição em ordem. Para a primeira condição que for true (diferente de zero e não NULL), retorna o valor correspondente.
Se nenhuma das condições for true, retorna o valor de else.
A configuração short_circuit_function_evaluation controla
se a avaliação de curto-circuito é usada. Se estiver ativada, a expressão then_i será avaliada apenas nas linhas em que
((NOT cond_1) AND ... AND (NOT cond_{i-1}) AND cond_i) for true.
Por exemplo, com avaliação de curto-circuito, nenhuma exceção de divisão por zero é lançada ao executar a seguinte consulta:
SELECT multiIf(number = 2, intDiv(1, number), number = 5) FROM numbers(10)Todas as expressões dos ramos e do else devem ter um supertipo comum. As condições NULL são tratadas como falsas.
Sintaxe
multiIf(cond_1, then_1, cond_2, then_2, ..., else)Aliases: caseWithoutExpression, caseWithoutExpr
Argumentos
cond_N— A enésima condição avaliada, que determina sethen_Nserá retornado.UInt8ouNullable(UInt8)ouNULLthen_N— O resultado da função quandocond_Né true. -else— O resultado da função se nenhuma das condições for true.
Valor retornado
Retorna o resultado de then_N para o cond_N correspondente; caso contrário, retorna o resultado de else.
Exemplos
Exemplo de uso
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;┌─left─┬─right─┬─result──────────┐
│ ᴺᵁᴸᴸ │ 4 │ Null value │
│ 1 │ 3 │ left is smaller │
│ 2 │ 2 │ Both equal │
│ 3 │ 1 │ left is greater │
│ 4 │ ᴺᵁᴸᴸ │ Null value │
└──────┴───────┴─────────────────┘