跳转到主要内容
ClickHouse 会在解析查询时,根据运算符的优先级、先后顺序和结合性,将其转换为相应的函数。

访问运算符

a[N] – 访问数组元素。arrayElement(a, N) 函数。 a.N – 访问Tuple元素。tupleElement(a, N) 函数。

数值取负运算符

-anegate(a) 函数。 有关 Tuple 取负,请参见:tupleNegate

乘法和除法运算符

a * bmultiply(a, b) 函数。 如需将Tuple乘以数值,请参见 tupleMultiplyByNumber;如需计算标量积,请参见 dotProduct a / bdivide(a, b) 函数。 如需将Tuple除以数值,请参见 tupleDivideByNumber a % bmodulo(a, b) 函数。

加法和减法运算符

a + bplus(a, b) 函数。 对于 Tuple 加法,请参见:tuplePlus a - bminus(a, b) 函数。 对于 Tuple 减法,请参见:tupleMinus

比较运算符

equals 函数

a = b – 表示 equals(a, b) 函数。 a == b – 表示 equals(a, b) 函数。

notEquals 函数

a != b – 表示 notEquals(a, b) 函数。 a <> b – 表示 notEquals(a, b) 函数。

lessOrEquals 函数

a <= b – 即 lessOrEquals(a, b) 函数。

greaterOrEquals 函数

a >= b —— greaterOrEquals(a, b) 函数。

less 函数

a < b —— less(a, b) 函数。

greater 函数

a > bgreater(a, b) 函数。

like 函数

a LIKE b —— 即 like(a, b) 函数。

notLike 函数

a NOT LIKE b —— 即 notLike(a, b) 函数。

ilike 函数

a ILIKE b —— 即 ilike(a, b) 函数。

BETWEEN 函数

a BETWEEN b AND c – 等同于 a >= b AND a <= c a NOT BETWEEN b AND c – 等同于 a < b OR a > c

is not distinct from 运算符 (<=>)

从 25.10 版本开始,你可以像使用其他运算符一样使用 <=>。 在 25.10 之前,它只能用于 JOIN 表达式,例如:
CREATE TABLE a (x String) ENGINE = Memory;
INSERT INTO a VALUES ('ClickHouse');

SELECT * FROM a AS a1 JOIN a AS a2 ON a1.x <=> a2.x;

┌─x──────────┬─a2.x───────┐
│ ClickHouse │ ClickHouse │
└────────────┴────────────┘
<=> 运算符是对 NULL 安全的相等运算符,等价于 IS NOT DISTINCT FROM。 它的行为与常规相等运算符 (=) 类似,但会将 NULL 值视为可比较的。 两个 NULL 值会被视为相等,而 NULL 与任何非 NULL 值比较时,返回 0 (false) 而不是 NULL
SELECT
  'ClickHouse' <=> NULL,
  NULL <=> NULL
┌─isNotDistinc⋯use', NULL)─┬─isNotDistinc⋯NULL, NULL)─┐
│                        0 │                        1 │
└──────────────────────────┴──────────────────────────┘

用于处理字符串的运算符

OVERLAY

  • OVERLAY(string PLACING replacement FROM offset) - overlay(string, replacement, offset) 函数。
  • OVERLAY(string PLACING replacement FROM offset FOR length) - overlay(string, replacement, offset, length) 函数。
  • OVERLAYUTF8(string PLACING replacement FROM offset) - overlayUTF8(string, replacement, offset) 函数。
  • OVERLAYUTF8(string PLACING replacement FROM offset FOR length) - overlayUTF8(string, replacement, offset, length) 函数。

用于处理数据集的运算符

请参阅 IN 运算符EXISTS 运算符。

in 函数

a IN ... —— in(a, b) 函数。

notIn 函数

a NOT IN ... —— notIn(a, b) 函数。

globalIn 函数

a GLOBAL IN ...globalIn(a, b) 函数。

globalNotIn 函数

a GLOBAL NOT IN ... —— globalNotIn(a, b) 函数。

in 子查询函数

a = ANY (subquery) – 即 in(a, subquery) 函数。

notIn 子查询函数

a != ANY (subquery) —— 与 a NOT IN (SELECT singleValueOrNull(*) FROM subquery) 相同。

in 子查询函数

a = ALL (subquery) – 等同于 a IN (SELECT singleValueOrNull(*) FROM subquery)

notIn 子查询函数

a != ALL (subquery) —— 即 notIn(a, subquery) 函数。 示例 带有 ALL 的查询:
Query
SELECT number AS a FROM numbers(10) WHERE a > ALL (SELECT number FROM numbers(3, 3));
Response
┌─a─┐
│ 6 │
│ 7 │
│ 8 │
│ 9 │
└───┘
带有 ANY 的查询:
Query
SELECT number AS a FROM numbers(10) WHERE a > ANY (SELECT number FROM numbers(3, 3));
Response
┌─a─┐
│ 4 │
│ 5 │
│ 6 │
│ 7 │
│ 8 │
│ 9 │
└───┘

数组上的 SOME / ALL

除了上文描述的子查询形式外,SOME / ALL 的右侧也可以是数组表达式 (数组字面量、数组类型的列,或任何返回数组的表达式) 。这是 PostgreSQL 风格的数组量词语法。它会在解析时被识别并重写为数组函数,因此无需手动重写:
SyntaxRewritten to
expr = SOME(arr)has(arr, expr)
expr <> ALL(arr)NOT has(arr, expr)
expr OP SOME(arr) (any other comparison operator)arrayExists(x -> expr OP x, arr)
expr OP ALL(arr) (any other comparison operator)arrayAll(x -> expr OP x, arr)
SOME 是存在量词 (即 SQL 中 ANY 的同义词) 。=<> 会被特殊处理为 has / NOT has,因为它们有经过优化的实现;一般形式则会退回到高阶 arrayExists / arrayAll 函数。 数组形式仅对比较运算符 =, ==, !=, <>, <=>, <, <=, >, 和 >= 生效。其他支持右侧为数组的运算符——例如 LIKEILIKENOT LIKEREGEXPIN——不会 被重写为数组量词,而是保留其原本含义。例如,'abc' LIKE SOME(['a%', 'b%']) 并不是数组量词语法;对于这些情况,请直接使用 arrayExists / arrayAll
数组形式不支持 ANY只有 SOMEALL 接受右侧为数组。之所以排除 ANY,是因为 any 同时也是一个 aggregate function,因此形态为 expr = any(x) 的表达式会保留其函数调用含义。要使用数组量词,请使用 SOME
Query
SELECT
    3 = SOME([1, 2, 3, 4]) AS in_array,
    5 < SOME([1, 2, 6])    AS less_than_some,
    5 > ALL([1, 2, 3])     AS greater_than_all;
Response
┌─in_array─┬─less_than_some─┬─greater_than_all─┐
│        1 │              1 │                1 │
└──────────┴────────────────┴──────────────────┘
NULL 的处理与子查询形式不同由于数组形式会在 parser 中被重写 (此时无法使用 transform_null_in 之类的查询设置,而且按行处理的数组列也无法走 analyzer 的 NULL 安全 IN 路径) ,它采用的是 has (用于 = / <>) 以及 arrayExists / arrayAll 的二值语义 (会将结果未知的 NULL 比较折叠为 0) 。这可能与子查询形式不同:后者对 NULL 的处理会经由 IN / NOT IN 进行转换,并取决于 transform_null_in
SELECT NULL = SOME([NULL]);   -- has([NULL], NULL)                  -> 1
SELECT NULL <> ALL([NULL]);   -- NOT has([NULL], NULL)              -> 0
SELECT NULL < SOME([1]);      -- arrayExists(x -> NULL < x, [1])    -> 0
SELECT NULL > ALL([1]);       -- arrayAll(x -> NULL > x, [1])       -> 0

日期和时间运算符

EXTRACT

EXTRACT(part FROM date);
从给定的日期中提取指定部分。例如,您可以从给定日期中提取月份,或从时间中提取秒。 part 参数指定要提取日期的哪个部分。可用值如下:
  • NANOSECOND — 纳秒。可能的值:0–999999999。
  • MICROSECOND — 微秒。可能的值:0–999999。
  • MILLISECOND — 毫秒。可能的值:0–999。
  • SECOND — 秒。可能的值:0–59。
  • MINUTE — 分钟。可能的值:0–59。
  • HOUR — 小时。可能的值:0–23。
  • DAY — 月中的第几天。可能的值:1–31。
  • WEEK — ISO 8601 周数。可能的值:1–53。
  • MONTH — 月份编号。可能的值:1–12。
  • QUARTER — 季度。可能的值:1–4。
  • YEAR — 年。
  • EPOCH — Unix 时间戳 (自 1970-01-01 00:00:00 UTC 起的秒数) 。注意:对于 DateTime64,秒以下部分会被截断。
  • DOW — 一周中的第几天 (与 PostgreSQL 兼容) 。0 = 星期日,6 = 星期六。
  • DOY — 一年中的第几天。可能的值:1–366。
  • ISODOW — ISO 一周中的第几天。1 = 星期一,7 = 星期日。
  • ISOYEAR — ISO 8601 周编号年份。
  • CENTURY — 世纪。例如,2024 年属于 21 世纪。
  • DECADE — 十年 (年份除以 10) 。例如,2024 年的十年值为 202。
  • MILLENNIUM — 千年。例如,2024 年属于第 3 个千年。
  • TIMEZONE_HOUR — 操作数时区的 UTC 偏移中带符号的小时部分。例如,+5:30 返回 5-3:30 返回 -3
  • TIMEZONE_MINUTE — 操作数时区的 UTC 偏移中带符号的分钟部分。例如,+5:30 返回 30-3:30 返回 -30
part 参数不区分大小写。 date 参数指定要处理的值。支持 DateDate32DateTimeDateTime64Interval 类型。当 dateInterval 时,请求的 part 必须与该 Interval 存储的种类一致 (例如,允许 EXTRACT(DAY FROM INTERVAL 5 DAY);会拒绝 EXTRACT(HOUR FROM INTERVAL 5 DAY),因为 ClickHouse 的 interval 只支持单一种类) 。Interval 操作数的结果为 Int64 示例:
SELECT EXTRACT(DAY FROM toDate('2017-06-15'));
SELECT EXTRACT(MONTH FROM toDate('2017-06-15'));
SELECT EXTRACT(YEAR FROM toDate('2017-06-15'));
SELECT EXTRACT(EPOCH FROM toDateTime('2024-01-15 12:30:45', 'UTC'));
SELECT EXTRACT(DOW FROM toDate('2024-01-15'));
SELECT EXTRACT(CENTURY FROM toDate('2024-01-01'));
SELECT EXTRACT(TIMEZONE_HOUR   FROM toDateTime('2024-01-15 12:00:00', 'Asia/Kolkata'));    -- 5
SELECT EXTRACT(TIMEZONE_MINUTE FROM toDateTime('2024-01-15 12:00:00', 'Asia/Kolkata'));    -- 30
SELECT EXTRACT(DAY   FROM INTERVAL 40 DAY);                                                -- 40
SELECT EXTRACT(MONTH FROM INTERVAL 7 MONTH);                                               -- 7
在以下示例中,我们将创建一个表,并向其中插入一个 DateTime 类型的值。
CREATE TABLE test.Orders
(
    OrderId UInt64,
    OrderName String,
    OrderDate DateTime
) ENGINE = MergeTree
ORDER BY ();
INSERT INTO test.Orders VALUES (1, 'Jarlsberg Cheese', toDateTime('2008-10-11 13:23:44'));
SELECT
    toYear(OrderDate) AS OrderYear,
    toMonth(OrderDate) AS OrderMonth,
    toDayOfMonth(OrderDate) AS OrderDay,
    toHour(OrderDate) AS OrderHour,
    toMinute(OrderDate) AS OrderMinute,
    toSecond(OrderDate) AS OrderSecond
FROM test.Orders;
┌─OrderYear─┬─OrderMonth─┬─OrderDay─┬─OrderHour─┬─OrderMinute─┬─OrderSecond─┐
│      2008 │         10 │       11 │        13 │          23 │          44 │
└───────────┴────────────┴──────────┴───────────┴─────────────┴─────────────┘
你可以在 tests 中查看更多示例。

INTERVAL

创建一个 Interval 类型的值,用于与 DateDateTime 类型的值进行算术运算。 时间间隔类型:
  • SECOND
  • MINUTE
  • HOUR
  • DAY
  • WEEK
  • MONTH
  • QUARTER
  • YEAR
设置 INTERVAL 值时,也可以使用字符串字面量。例如,INTERVAL 1 HOURINTERVAL '1 hour'INTERVAL '1' hour 完全等价。
不同类型的时间间隔不能组合使用。不能使用 INTERVAL 4 DAY 1 HOUR 这样的表达式。请使用小于或等于该时间间隔最小单位的单位来指定时间间隔,例如 INTERVAL 25 HOUR。你也可以像下面的示例那样,连续使用多个运算。
示例:
SELECT now() AS current_date_time, current_date_time + INTERVAL 4 DAY + INTERVAL 3 HOUR;
┌───current_date_time─┬─plus(plus(now(), toIntervalDay(4)), toIntervalHour(3))─┐
│ 2020-11-03 22:09:50 │                                    2020-11-08 01:09:50 │
└─────────────────────┴────────────────────────────────────────────────────────┘
SELECT now() AS current_date_time, current_date_time + INTERVAL '4 day' + INTERVAL '3 hour';
┌───current_date_time─┬─plus(plus(now(), toIntervalDay(4)), toIntervalHour(3))─┐
│ 2020-11-03 22:12:10 │                                    2020-11-08 01:12:10 │
└─────────────────────┴────────────────────────────────────────────────────────┘
SELECT now() AS current_date_time, current_date_time + INTERVAL '4' day + INTERVAL '3' hour;
┌───current_date_time─┬─plus(plus(now(), toIntervalDay('4')), toIntervalHour('3'))─┐
│ 2020-11-03 22:33:19 │                                        2020-11-08 01:33:19 │
└─────────────────────┴────────────────────────────────────────────────────────────┘
始终建议优先使用 INTERVAL 语法或 addDays 函数。简单的加减运算 (如 now() + ... 这样的写法) 不会考虑时间设置,例如夏令时。
示例:
SELECT toDateTime('2014-10-26 00:00:00', 'Asia/Istanbul') AS time, time + 60 * 60 * 24 AS time_plus_24_hours, time + toIntervalDay(1) AS time_plus_1_day;
┌────────────────time─┬──time_plus_24_hours─┬─────time_plus_1_day─┐
│ 2014-10-26 00:00:00 │ 2014-10-26 23:00:00 │ 2014-10-27 00:00:00 │
└─────────────────────┴─────────────────────┴─────────────────────┘
另请参阅

日期与时间相加

可以使用 + 运算符将 DateDate32 值与 TimeTime64 值相加。结果为 DateTimeDateTime64,表示该日期中给定时刻的日期时间值。该运算满足交换律。 结果类型取决于操作数类型:
Left operandRight operandResult type
DateTimeDateTime
DateTime64(s)DateTime64(s)
Date32TimeDateTime64(0)
Date32Time64(s)DateTime64(s)
结果使用会话时区 (如果未设置会话时区,则使用服务器默认时区) 。date_time_overflow_behavior设置控制结果超出可表示范围时的行为。
示例:
SET use_legacy_to_time = 0;
SELECT toDate('2024-07-15') + toTime('14:30:25') AS dt, toTypeName(dt);
┌──────────────────dt─┬─toTypeName(dt)─┐
│ 2024-07-15 14:30:25 │ DateTime       │
└─────────────────────┴────────────────┘
SELECT toDate('2024-07-15') + toTime64('14:30:25.123456', 6) AS dt, toTypeName(dt);
┌─────────────────────────dt─┬─toTypeName(dt)─┐
│ 2024-07-15 14:30:25.123456 │ DateTime64(6)  │
└────────────────────────────┴────────────────┘
SELECT toTime64('23:59:59.999', 3) + toDate32('2024-07-15') AS dt, toTypeName(dt);
┌──────────────────────dt─┬─toTypeName(dt)─┐
│ 2024-07-15 23:59:59.999 │ DateTime64(3)  │
└─────────────────────────┴────────────────┘

逻辑 AND 运算符

语法 SELECT a AND b — 使用函数 and 计算 ab 的逻辑与。

逻辑 OR 运算符

语法 SELECT a OR b — 使用函数 or 计算 ab 的逻辑或。

逻辑非运算符

语法 SELECT NOT a — 使用函数 nota 进行逻辑非运算。

条件运算符

a ? b : cif(a, b, c) 函数。 注意: 条件运算符会先计算 b 和 c 的值,再检查是否满足条件 a,然后返回对应的值。如果 bCarrayJoin() 函数,则无论 “a” 条件是否成立,每一行都会被复制。

条件表达式

CASE [x]
    WHEN a THEN b
    [WHEN ... THEN ...]
    [ELSE c]
END
如果指定了 x,则使用 transform(x, [a, ...], [b, ...], c) 函数。否则,使用 multiIf(a, b, ..., c) 如果表达式中没有 ELSE c 子句,默认值为 NULL transform 函数不支持 NULL

拼接运算符

s1 || s2concat(s1, s2) 函数。

Lambda 创建运算符

x -> exprlambda(x, expr) 函数。 以下运算符没有优先级,因为它们是括号:

数组创建运算符

[x1, ...]array(x1, ...) 函数。

Tuple 创建运算符

(x1, x2, ...) – 即 tuple(x2, x2, ...) 函数。

结合性

所有二元运算符都是左结合的。例如,1 + 2 + 3 会被转换为 plus(plus(1, 2), 3)。 但有时结果可能不符合你的预期。例如,SELECT 4 > 2 > 3 的结果将为 0。 出于效率考虑,andor 函数可以接受任意数量的参数。相应的 ANDOR 运算符链会被转换为对这些函数的一次调用。

检查 NULL

ClickHouse 支持 IS NULLIS NOT NULL 运算符。

IS NULL

  • 对于 Nullable 类型的值,IS NULL 运算符返回:
    • 如果值为 NULL,则返回 1
    • 否则返回 0
  • 对于其他值,IS NULL 运算符始终返回 0
可通过启用 optimize_functions_to_subcolumns 设置来优化。将 optimize_functions_to_subcolumns = 1 时,该函数只会读取 null 子列,而不是读取并处理整个列数据。查询 SELECT n IS NULL FROM table 会被转换为 SELECT n.null FROM TABLE
SELECT x+100 FROM t_null WHERE y IS NULL
┌─plus(x, 100)─┐
│          101 │
└──────────────┘

IS NOT NULL

  • 对于 Nullable 类型的值,IS NOT NULL 运算符返回:
    • 如果该值为 NULL,则返回 0
    • 否则返回 1
  • 对于其他值,IS NOT NULL 运算符始终返回 1
SELECT * FROM t_null WHERE y IS NOT NULL
┌─x─┬─y─┐
│ 2 │ 3 │
└───┴───┘
可通过启用 optimize_functions_to_subcolumns 设置进行优化。将 optimize_functions_to_subcolumns = 1 时,该函数仅读取 null 子列,而不是读取并处理整个列数据。查询 SELECT n IS NOT NULL FROM table 会被转换为 SELECT NOT n.null FROM TABLE

检查布尔值

ClickHouse 支持 IS TRUEIS FALSEIS UNKNOWNIS NOT TRUEIS NOT FALSEIS NOT UNKNOWN 运算符。 它们可与 BoolNullable(Bool) 表达式一起使用。
  • expr IS TRUE 仅当 exprtrue 时返回 1
  • expr IS FALSE 仅当 exprfalse 时返回 1
  • expr IS UNKNOWN 仅当 exprNULL 时返回 1
  • expr IS NOT TRUEexprfalseNULL 时返回 1
  • expr IS NOT FALSEexprtrueNULL 时返回 1
  • expr IS NOT UNKNOWNexpr 不为 NULL 时返回 1
对于布尔表达式,IS UNKNOWN 等同于 IS NULL,而 IS NOT UNKNOWN 等同于 IS NOT NULL
CREATE TABLE t_bool (x Nullable(Bool)) ENGINE = Memory;
INSERT INTO t_bool VALUES (true), (false), (NULL);

SELECT
    x,
    x IS TRUE,
    x IS FALSE,
    x IS UNKNOWN,
    x IS NOT TRUE,
    x IS NOT FALSE,
    x IS NOT UNKNOWN
FROM t_bool;
最后修改于 2026年6月25日