概要
条件式の結果をそのまま使用する
条件式の結果は常に 0、1、または NULL です。そのため、条件式の結果は次のようにそのまま使用できます。
SELECT left < right AS is_small
FROM LEFT_RIGHT
┌条件式における NULL 値
条件式に NULL 値が含まれる場合、結果も NULL になります。
SELECT
NULL < 1,
2 < NULL,
NULL < NULL,
NULL = NULL
┌したがって、types が Nullable の場合は、クエリを慎重に組み立てる必要があります。
次の例では、multiIf に等価条件を追加していないために失敗することを示しています。
SELECT
left,
right,
multiIf(left < right, 'left is smaller', left > right, 'right is smaller', 'Both equal') AS faulty_result
FROM LEFT_RIGHT
┌CASE ステートメント
ClickHouse の CASE 式は、SQL の CASE 演算子と同様の条件分岐ロジックを提供します。条件を評価し、最初に一致した条件に基づいて値を返します。
ClickHouse は 2 種類の CASE をサポートしています。
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
┌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
┌この形式では、返される式も定数である必要はありません。
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
┌注意点
ClickHouse は、CASE 式 (または multiIf などの内部的に等価な処理) の結果の型を、条件を評価する前に決定します。これは、返される式の型が異なる場合、たとえばタイムゾーンや数値型が異なる場合に重要です。
- 結果の型は、すべての分岐の中で互換性のある最も大きい型に基づいて選択されます。
- いったんこの型が選択されると、他のすべての分岐は暗黙的にその型にキャストされます。実行時にそのロジックが決して実行されない場合でも同様です。
- 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
┌ここで 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
┌clamp
導入バージョン: v24.5.0
値を指定された最小値と最大値の範囲内に制限します。
値が最小値未満の場合は最小値を返します。値が最大値を超える場合は最大値を返します。それ以外の場合は、値自体を返します。
すべての引数は比較可能な型である必要があります。結果の型は、すべての引数の中で最も広い互換型になります。
構文
clamp(value, min, max)引数
value— 制限する値。 -min— 下限値。 -max— 上限値。
戻り値
[min, max] の範囲に制限された値を返します。
例
基本的な使い方
SELECT clamp(5, 1, 10) AS result;┌─result─┐
│ 5 │
└────────┘値が最小値未満です
SELECT clamp(-3, 0, 7) AS result;┌─result─┐
│ 0 │
└────────┘最大値を超えた値
SELECT clamp(15, 0, 7) AS result;┌─result─┐
│ 7 │
└────────┘greatest
導入バージョン: v1.1.0
引数の中で最も大きい値を返します。
NULL 引数は無視されます。
- 配列の場合、辞書順で最大の配列を返します。
DateTime型では、結果の型は最大の型に昇格します (たとえば、DateTime32と混在する場合はDateTime64) 。
構文
greatest(x1[, x2, ...])引数
x1[, x2, ...]— 比較する 1 つ以上の値。すべての引数は比較可能な型である必要があります。Any
戻り値
引数の中で最も大きい値を返します。戻り値の型は、最も広い互換型に昇格されます。Any
例
数値型
-- 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 │
└────────┴─────────┘Array
SELECT greatest(['hello'], ['there'], ['world']);┌─greatest(['hello'], ['there'], ['world'])─┐
│ ['world'] │
└───────────────────────────────────────────┘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
導入バージョン: v1.1.0
条件分岐を行います。
- 条件
condが非ゼロの値として評価された場合、この関数は式thenの結果を返します。 condが 0 または NULL として評価された場合は、式elseの結果が返されます。
設定 short_circuit_function_evaluation では、短絡評価を使用するかどうかを制御します。
有効な場合、式 then は cond が true の行でのみ評価され、式 else は cond が false の行でのみ評価されます。
たとえば、短絡評価を使用すると、次のクエリを実行してもゼロ除算の例外はスローされません。
SELECT if(number = 0, 0, intDiv(42, number)) FROM numbers(10)then と else は同様の型である必要があります。
構文
if(cond, then, else)引数
cond— 評価される条件。UInt8、Nullable(UInt8)、またはNULLthen—condが true の場合に返される式。 -else—condが false またはNULLの場合に返される式。
戻り値
条件 cond に応じて、then または else の式の結果を返します。
例
使用例
SELECT if(1, 2 + 2, 2 + 6) AS res;┌─res─┐
│ 4 │
└─────┘least
導入バージョン: v1.1.0
引数の中で最も小さい値を返します。
NULL の引数は無視されます。
- 配列の場合、辞書順で最小の配列を返します。
- DateTime型の場合、結果の型は最大の型に昇格されます (たとえば、DateTime32 と混在している場合は DateTime64) 。
構文
least(x1[, x2, ...])引数
x1[, x2, ...]— 比較する単一の値または複数の値。すべての引数は、比較可能な型である必要があります。Any
戻り値
引数の中で最も小さい値を返します。戻り値の型は、最も広い互換型に昇格されます。Any
例
数値型
-- 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 │
└────────┴─────────┘Array
SELECT least(['hello'], ['there'], ['world']);┌─least(['hello'], ['there'], ['world'])─┐
│ ['hello'] │
└────────────────────────────────────────┘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
導入バージョン: v1.1.0
クエリ内で CASE 演算子をより簡潔に記述できます。
各条件は順番に評価されます。最初に true (非ゼロかつ NULL ではない) となった条件に対応する分岐値を返します。
いずれの条件も true でない場合は、else の値を返します。
設定 short_circuit_function_evaluation は、
短絡評価を使用するかどうかを制御します。有効な場合、then_i 式は
((NOT cond_1) AND ... AND (NOT cond_{i-1}) AND cond_i) が true になる行でのみ評価されます。
たとえば、短絡評価を使用すると、次のクエリを実行してもゼロ除算例外は発生しません。
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_N—then_Nを返すかどうかを制御する、N 番目に評価される条件。UInt8またはNullable(UInt8)またはNULLthen_N—cond_Nが true の場合に返される関数の結果。 -else— どの条件も true でない場合の関数の結果。
戻り値
一致した cond_N に対応する then_N の結果を返し、どれにも一致しない場合は else の結果を返します。
例
使用例
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 │
└──────┴───────┴─────────────────┘