IN 操作符
该 IN
, NOT IN
, GLOBAL IN
,和 GLOBAL NOT IN
运算符是单独考虑的,因为它们的功能相当丰富。
运算符的左侧是单列或元组。
例:
SELECT UserID IN (123, 456) FROM ...
SELECT (CounterID, UserID) IN ((34, 123), (101500, 456)) FROM ...
如果左侧是索引中的单列,而右侧是一组常量,则系统将使用索引处理查询。
请不要列举太多具体的常量 (比方说 几百万条)。如果数据集非常大,请把它放在一张临时表里(例如,参考章节用于查询处理的外部数据),然后使用子查询。
运算符的右侧可以是一组常量表达式、一组带有常量表达式的元组(如上面的示例所示),或括号中的数据库表或SELECT子查询的名称。
如果运算符的右侧是表的名称(例如, UserID IN users
),这相当于子查询 UserID IN (SELECT * FROM users)
. 使用与查询一起发送的外部数据时,请使用此选项。 例如,查询可以与一组用户Id一起发送到 ‘users’ 应过滤的临时表。
如果 运算符的右侧是具有Set引擎的表名(始终位于RAM中的准备好的数据集),则不会为每个查询重新创建数据集。
子查询可以指定多个用于筛选元组的列。 示例:
SELECT (CounterID, UserID) IN (SELECT CounterID, UserID FROM ...) FROM ...
IN运算符左侧和右侧的列应具有相同的类型。
IN运算符和子查询可能出现在查询的任何部分,包括聚合函数和lambda函数。 示例:
SELECT
EventDate,
avg(UserID IN
(
SELECT UserID
FROM test.hits
WHERE EventDate = toDate('2014-03-17')
)) AS ratio
FROM test.hits
GROUP BY EventDate
ORDER BY EventDate ASC
┌──EventDate─┬────ratio─┐
│ 2014-03-17 │ 1 │
│ 2014-03-18 │ 0.807696 │
│ 2014-03-19 │ 0.755406 │
│ 2014-03-20 │ 0.723218 │
│ 2014-03-21 │ 0.697021 │
│ 2014-03-22 │ 0.647851 │
│ 2014-03-23 │ 0.648416 │
└────────────┴──────────┘
对于3月17日后的每一天,计算3月17日访问该网站的用户所做的浏览量百分比。 IN子句中的子查询始终只在单个服务器上运行一次。 没有依赖子查询。
空处理
在请求处理过程中, IN
运算符假定运算的结果 NULL 总是等于 0
,无论是否 NULL
位于操作员的右侧或左侧。 NULL
值不包含在任何数据集中,彼此不对应,并且在以下情况下无法进行比较 transform_null_in=0.
下面是一个例子 t_null
表:
┌─x─┬────y─┐
│ 1 │ ᴺᵁᴸᴸ │
│ 2 │ 3 │
└───┴──────┘
运行查询 SELECT x FROM t_null WHERE y IN (NULL,3)
为您提供以下结果:
┌─x─┐
│ 2 │
└───┘
你可以看到,在其中的行 y = NULL
被抛出的查询结果。 这是因为ClickHouse无法决定是否 NULL
包含在 (NULL,3)
设置,返回 0
作为操作的结果,和 SELECT
从最终输出中排除此行。
SELECT y IN (NULL, 3)
FROM t_null
┌─in(y, tuple(NULL, 3))─┐
│ 0 │
│ 1 │
└───────────────────────┘