Clickhouse 中至少有2中类型的函数
-正常函数(被称为 functions)和聚合函数.
这两个函数完全不同。正常函数被应用到每行(对于每行,函数的结果不依赖与其他行).聚合函数从不同的行中累计相应的值(例如. 他们依赖整个行的集合). 在本章中,我们将讨论正常函数. 对于聚合函数, 查看章节"Aggregate functions". *
- 有第三种函数的类型, 'arrayJoin'函数属于; 表函数也能够被单独提及.
强类型
与标准的 SQL 不同, ClickHouse 有强类型. 换句话说, 它不能在类型之间进行隐式转换. 每个函数可以运行在不同数据类型之上. 这意味着有时你需要使用类型转换函数.
通用的子表达消除
在一个查询中所有的表达式都有相同的 AST (相同的记录或者相同的语法解析) 能够被考虑有完全相同的值. 这些表达式可以拼接的,一次执行. 相同的子查询也能够按照相同的方式消除.
结果类型
所有的函数返回一个单值作为结果 (不是多个值,也不是0值). 通常情况下,结果的类型仅通过参数的类型来定义, 不通过值来定义. 异常是 tupleElement 函数 (a.N 操作符), 同时是 toFixedString 函数.
常量
为了简化, 某些函数的参数仅能带有常数工作. 例如, LIKE 操作符的右侧参数必须是一个常数. 对于常数参数, 几乎所有的函数返回一个常数. 异常是一个函数,可生成随机数. 对于查询来说, ’now' 函数返回不同的值,如果运行在不同的时间点上,但是结果是一个常数, 常数仅在一次查询内是重要的. 一个常数表达式也考虑到一个常数 (例如, LIKE 操作符右侧从多个常量中构建). 函数能够以不同的方式实现,可带有常数和非常数参数. 但是对于一个常数的结果,对于一个仅包含相同值的列应该互相匹配.
不可变性
对于这些参数, 函数不能改变值
-任何的改变作为结果返回. 因此, 计算不同的函数的结果不依赖哪个函数写到了查询中.
错误处理
一些函数可能抛出一些异常 如果数据是无效的. 在这种情况下, 查询被计算,错误文本将返回给客户端. 对于分布式处理,当一个异常在一个服务器中发生时, 其他服务器也放弃这个查询.
参数表达式赋值
在大多数编程语言中, 对于某些操作符一个参数可能并不被赋值. 通常情况下,对于操作符 &&, ||, ?:. 但是在 ClickHouse 中, 函数的参数 (操作符) 通常是被赋值的. 这是因为列的整个部分被一次性赋值, 而不是单独计算每个行.
为分布式查询处理执行函数
对于分布式查询处理, 查询处理的多个阶段尽量执行在远程服务器上, 剩下的阶段被处理在请求服务器上 (合并中间结果和后续处理) . 这意味着函数能够被执行在不同的服务器上. 例如, 在查询中SELECTf(sum(g(x)))FROM distributed_table GROUP BYh(y),
-如果%%distributed_table%%有至少2个分片,此函数%%g%%和%%h%%在远程服务器上被执行,同时函数%%f%% -在请求服务器上执行.
- 如果 %%distributed_table%% 仅有一个分片, 所有的函数 %%f%%, %%g%%, 和 %%h%% 在这个分片服务器上执行. 函数的结果通常不依赖于哪个服务器执行. 然而, 优势这个非常重要的. 例如, 函数使用词典, 词典存在于服务器内. 另外一个例子是 %%hostName%% 函数, 返回服务器的名称为了通过服务器进行GROUP BY汇总查询. 如果在查询中一个函数在请求服务器中被执行, 但是你需要在远程服务器上处理, 你能够封装它到任意的聚合函数中或者添加到GROUP BY的一个 Key 中.
算术函数
对于所有的算术函数, 结果类型被计算作为适合结果的最小数字类型, 如果有这样一个类型. 最小值基于bits位数, 是否它被分配, 是否它是浮点数. 如果没有足够的 bits 位数, 最高的 bit 类型被采纳. 例如:
SELECT toTypeName(0), toTypeName(0+0), toTypeName(0+0+0), toTypeName(0+0+0+0)
┌─toTypeName(0)─┬─toTypeName(plus(0, 0))─┬─toTypeName(plus(plus(0, 0), 0))─┬─toTypeName(plus(plus(plus(0, 0), 0), 0))─┐
│UInt8 │UInt16 │UInt32 │UInt64 │
└───────────────┴────────────────────────┴─────────────────────────────────┴──────────────────────────────────────────┘
算数函数为如下任意类型的服务UInt8,UInt16,UInt32,UInt64,Int8,Int16,Int32,Int64,Float32,or Float64。Overflow以C++的方式被生成。
plus(a,b),a + b 操作符
计算数字的总和。你也可以添加带有Date或DateTime的整个数字。对于 Date 类型,添加一个整个数字意味着添加对应的天数。意味着添加对应的秒数。
minus(a,b),a - b 操作符
计算不同.此结果通常是signed.你也能够从date或datetime类型上计算整个数字.想法是相同的-查看以上的'plus'.
multiply(a,b),a * b 操作符
计算数字相乘.
divide(a,b),a / b 操作符
计算数字相除. 结果类型经常是一个浮点类型. 不是整数相除. 对于整数相除, 使用 'intDiv' 函数. 当除以0时,结果为 'inf', '-inf', 或者'nan'.
intDiv(a,b)
计算商数. 除以整数, 四舍五入(通过绝对值). 当除以0或最小负整数时,抛出异常.
计算数字的商。
intDivOrZero(a,b)
不同于 'intDiv' ,它将返回0,当除以0或当除以一个最小负整数时.
modulo(a,b),a % b操作符
在相除之后计算剩余数. 如果参数是浮点数, 它们先转换为整数,通过去除浮点精度部分. 剩余数与C++处理方式相同. 截断相除用于负数. 一个异常将要抛出,当除以0或者当除以最小负数.
negate(a),-a 操作符
计算一个带有反符号的数字. 结果经常带有符号.
abs(a)操作符
计算一个数的绝对值'a'. 如果 a< 0, 它将返回 -a. 对于非符号类型, 什么都不做. 对于符号整型类型, 将返回非符号数字.
gcd(a, b)操作符
返回数字最通用的除数. 当除以0或当除以最小负数后,异常将抛出.
lcm(a, b)
返回最通用的乘数. 当除以0或当除以最小负数后,异常将抛出.
Bit 函数
Bit函数服务于UInt8,UInt16,UInt32,UInt64,Int8,Int16,Int32,Int64,Float32,或者Float64.结果类型是一个带有位数的整型,与参数的最大位数相等.如果至少有一个参数被指定,结果将是一个符号化数字.如果一个参数是一个浮点数,它将转换到Int64.
为数组服务的函数
empty
为空数组返回1,对于非空数组返回0。结果类型是UInt8。该函数也适用于字符串。
notEmpty
对于空数组返回0,对于非空数组返回1。结果类型是UInt8。该函数也适用于字符串。
length
返回数组中的项目数。结果类型是UInt64。该函数也适用于字符串。
emptyArrayUInt8, emptyArrayUInt16, emptyArrayUInt32, emptyArrayUInt64
emptyArrayInt8, emptyArrayInt16, emptyArrayInt32, emptyArrayInt64
emptyArrayFloat32, emptyArrayFloat64
emptyArrayDate, emptyArrayDateTime
emptyArrayString
接受零参数并返回相应类型的空数组。
emptyArrayToSingle
接受一个空数组并返回一个等于默认值的一个元素的数组。
range(N)
返回从0到N-1的数字数组。以防万一,如果在数据块中创建总长度超过100,000,000个元素的数组,则会引发异常。
array(x1, ...), оператор [x1, ...]
从函数参数创建一个数组。参数必须是常量,并且具有最小通用类型的类型。必须至少传递一个参数,否则不清楚创建哪种类型的数组。也就是说,你不能使用这个函数来创建一个空数组(为此,使用上面描述的'emptyArray *'函数)。返回一个“Array(T)”类型结果,其中“T”是传递参数中最小的通用类型。
arrayConcat
绑定作为参数传递的数组.
arrayConcat(arrays)
Arguments
arrays – 逗号分隔的数组[值].
Example
SELEC TarrayConcat([1,2],[3,4],[5,6]) AS res
┌─res───────────┐│ [1,2,3,4,5,6] │└───────────────┘
arrayElement(arr, n), 操作符 arr[n]
从数组'arr'中获取索引为'n'的元素。'n'必须是任何整数类型。数组中的索引从1开始。支持负数索引。在这种情况下,它从末尾选择相应的元素。例如,'arr [-1]'是数组中的最后一项。
如果索引落在数组边界之外,它将返回一些默认值(数字为0,字符串为空字符串等)。
has(arr, elem)
检查'arr'数组是否有'elem'元素。如果元素不在数组中,则返回0;如果在数组中,则返回1。
indexOf(arr, x)
如果它在数组中,则返回“x”元素的索引(从1开始);如果不在数组中,则返回0。
countEqual(arr, x)
返回数组中的等于 x 的元素数量. 等于 arrayCount (elem->elem = x, arr).
arrayEnumerate(arr)
返回数组 [1, 2, 3, ..., length (arr) ]
函数通常被用于ARRAY JOIN。它允许为每个数组计算 count,在使用ARRAY JOIN后。例如:
SELECT count() AS Reaches,countIf(num=1) AS Hits FROM test.hits ARRAY JOIN GoalsReached,array Enumerate(GoalsReached) AS num WHERE CounterID=160656 LIMIT 10
┌─Reaches─┬──Hits─┐
│ 95606 │ 31406 │
└─────────┴───────┘
在这个例子中,Reaches是转换次数(应用ARRAY JOIN后收到的字符串),Hits是页面浏览量(ARRAY JOIN之前的字符串)。在这种情况下,您可以通过更简单的方式获得相同的结果:
SELECT sum(length(GoalsReached)) AS Reaches, count() AS Hits FROM test.hits WHERE(CounterID=160656) AND notEmpty(GoalsReached)
┌─Reaches─┬──Hits─┐
│ 95606 │ 31406 │
└─────────┴───────┘
该功能也可用于高阶功能。例如,您可以使用它来获取匹配条件的元素的数组索引。
arrayEnumerateUniq(arr, ...)
返回与源数组大小相同的数组,为每个元素指示其位置在具有相同值的元素中的位置。例如:arrayEnumerateUniq([10,20,10,30])= [1,1,2,1]。
使用ARRAY JOIN和数组元素聚合时,此函数很有用。例:
SELECT Goals.IDASGoalID, sum(Sign)ASReaches, sumIf(Sign,num=1) AS Visits FROM test.visits ARRAYJOIN Goals, arrayEnumerateUniq(Goals.ID) AS num WHERE CounterID = 160656 GROUP BY GoalID ORDERBY Reaches DESC LIMIT 10
┌──GoalID─┬─Reaches─┬─Visits─┐
│ 53225 │ 3214 │ 1097 │
│ 2825062 │ 3188 │ 1097 │
│ 56600 │ 2803 │ 488 │
│ 1989037 │ 2401 │ 365 │
│ 2830064 │ 2396 │ 910 │
│ 1113562 │ 2372 │ 373 │
│ 3270895 │ 2262 │ 812 │
│ 1084657 │ 2262 │ 345 │
│ 56599 │ 2260 │ 799 │
│ 3271094 │ 2256 │ 812 │
└─────────┴─────────┴────────┘
在这个例子中,每个目标ID都有一个转换次数的计算(目标嵌套数据结构中的每个元素都是达到的目标,我们称之为转换)以及会话数量。如果没有ARRAY JOIN,我们可以将会话的数量计算为总和(Sign)。但是在这种特殊情况下,行被嵌套的Goals结构乘以,所以为了在此之后计算每个会话一次,我们将一个条件应用到arrayEnumerateUniq(Goals.ID)函数的值。
arrayEnumerateUniq函数可以将多个大小相同的数组作为参数。在这种情况下,唯一性被考虑为所有数组中相同位置元素的元组。
SELECT array EnumerateUniq([1,1,1,2,2,2],[1,1,2,1,1,2]) AS res
┌─res───────────┐
│ [1,2,1,1,2,1] │
└───────────────┘
当使用ARRAY JOIN和嵌套的数据结构,并在这个结构中的多个元素之间进一步聚合时,这是必要的。
arrayPopBack
删除数组中的最后一项。
arrayPopBack(array)
参数
array – 数组.
例如
SELECT arrayPopBack([1,2,3]) AS res
┌─res───┐
│ [1,2] │
└───────┘
arrayPopFront
从数组中删除第一个元素
arrayPopFront(array)
参数
array – 数组.
示例
SELECT arrayPopFront([1,2,3]) AS res
┌─res───┐
│ [2,3] │
└───────┘
arrayPushBack
在数组的结尾添加一个元素
array PushBack(array,single_value)
参数
array – 数组.
single_value - 单个值。只有数字可以添加到数组中,只有将字符串添加到字符串数组中。在添加数字时,ClickHouse会自动为数组的数据类型设置single_value类型。有关ClickHouse中数据类型的更多信息,请参阅“数据类型”。
示例
SELECT arrayPushBack(['a'],'b') AS res
┌─res───────┐
│ ['a','b'] │
└───────────┘
arrayPushFront
在数组的开头添加一个元素
array PushFront(array,single_value)
array – 数组.
single_value - 单个值。只有数字可以添加到数组中,只有将字符串添加到字符串数组中。在添加数字时,ClickHouse会自动为数组的数据类型设置single_value类型。有关ClickHouse中数据类型的更多信息,请参阅“数据类型”。
示例
SELECT array PushBack(['b'],'a') AS res
┌─res───────┐
│ ['a','b'] │
└───────────┘
arraySlice
返回数组的切片.
arraySlice(array,offset[,length])
参数
array – 数组数据.
偏移量 - 从数组的边界偏移。正值表示左侧的偏移量,负值表示右侧的缩进量。数组项的编号从1开始。
长度 - 所需切片的长度。如果你指定一个负值,函数返回一个开放的片段[offset,array_length - length)。如果省略该值,则函数返回切片[offset,the_end_of_array]。
示例
SELECT arraySlice([1,2,3,4,5],2,3) AS res
┌─res─────┐
│ [2,3,4] │
└─────────┘
arrayUniq(arr, ...)
如果传递一个参数,它会计算数组中不同元素的数量。如果传递多个参数,它将计算多个数组中相应位置的元素的不同元组的数量。
如果你想得到一个数组中唯一元素的列表,你可以使用arrayReduce('groupUniqArray',arr)。
arrayJoin(arr)
一个特殊的函数. 请查看章节 "ArrayJoin function".