ClickHouse 字符串的相关操作函数(十二)
ClickHouse 字符串的相关操作函数(十二)
本文来源: ( https://www.cnblogs.com/traditional/tag/ClickHouse:一款速度快到让人发指的列式存储数据库/ )
楔子
下面来说一说字符串的相关操作。
empty:检测一个字符串是否为空,为空返回 1,不为空返回 0
notEmpty:检测一个字符串是否不为空,不为空返回 1,为空返回 0
1 | SELECT empty(''), empty('satori'); |
length:计算一个字符串占多少个字节
char_length:计算一个字符串占多少个字符
1 | WITH 'satori' AS s1, '古明地觉' AS s2 |
toString:将整型、日期转成字符串
1 | SELECT toString(3), cast(3 AS String); |
除了使用 cast 之外,每种数据类型都内置了相应的转换函数,格式为 to + 类型,比如 toInt8、toUInt32、toFloat64、toDecimal64 等等
lower、lcase:字符串转小写
upper、ucase:字符串转大写
1 | SELECT lower('SAtoRI'), upper('SAtoRI'); |
repeat:将字符串重复 n 次
1 | SELECT repeat('abc', 3); |
reverse:将字符串翻转
1 | SELECT reverse('satori'); |
注意:reverse 是按照字节翻转的,这意味着它不能用在中文上面,如果想翻转中文,那么要使用 reverseUTF8,可以试一下。
format:格式化字符串
1 | SELECT format('{}--{}', 'hello', 'world'); |
concat:拼接字符串
1 | SELECT concat('a', 'b', 'c'); |
当然拼接字符串还可以使用双竖线:
1 | SELECT 'a' || 'b' || 'c'; |
substring:字符串截取,也可以写成 mid、substr,用法和标准 SQL 中的 substring 一样,但有一点区别
1 | -- 从第 2 个元素开始截取,截取 3 个字节,注意:区别来了,截取的是字节 |
appendTrailingCharIfAbsent:如果非空字符串 s 的末尾不包含字符 c,那么就在 s 的结尾填上字符 c
1 | SELECT appendTrailingCharIfAbsent('satori', 'i'), |
convertCharset:改变字符串的字符集
1 | SELECT convertCharset('satori', 'ascii', 'utf8'); |
base64Encode:对字符串进行 base64 编码
base64Decode:对 base64 编码的字符串进行 base64 解码
1 | SELECT base64Encode('satori') s1, base64Decode(s1); |
还有一个 tryBase64Decode,和 base64Decode 类似,但解析失败时会返回空字符串。如果是 base64Decode,那么对一个非 base64 编码的字符串解析会得到乱码。
startsWith、endsWith:判断字符串是否以某个子串开头或结尾,如果是,返回 1;否则,返回 0
1 | SELECT startsWith('古明地觉', '古明') v1, endsWith('古明地觉', '古明') v2; |
trim:去除字符串两端的字符
1 | SELECT trim(' satori ') s, length(s); |
trim 如果只接收一个普通字符串,那么默认行为就是删除两端的空格,所以还有 trimLeft、trimRight,也是接收一个普通的字符串,然后去除左边、右边的空格。其中 trimLeft 也可以写作 ltrim,trimRight 也可以写作 rtrim。
CRC32:返回字符串的 CRC32 校验和,使用 CRC-32-IEEE 802.3 多项式,并且初始值为 0xFFFFFFFF
CRC32IEEE:返回字符串的 CRC32 校验和,使用 CRC-32-IEEE 802.3 多项式
CRC64:返回字符串的 CRC64 校验和,使用 CRC-64-ECMA 多项式
1 | SELECT CRC32('satori'), CRC32IEEE('satori'), CRC64('satori'); |
encodeXMLComponent:对字符串进行转义,针对 <、&、>、”、’ 五种符号
decodeXMLComponent:对字符串进行反转义,针对 <、&、>、”、’ 五种符号
1 | SELECT encodeXMLComponent('<name>'); |
position:查找某个子串在字符串当中的位置
1 | SELECT position('abcdefg', 'de'); |
该函数是大小写敏感的,如果想大小写不敏感,那么可以使用 positionCaseInsensitive。还有一点需要注意,该函数是按照字节统计的。
1 | position('古明地觉A', 'A') 得到的是 13,因为一个汉字 3 字节 |
如果包含中文,想按照字符统计,则需要使用 positionUTF8。
1 | positionUTF8('古明地觉A', 'A') 得到的就是 5 |
如果不存在,则返回 0
multiSearchAllPositions:查找多个子串在字符串当中的位置,多个子串组成数组进行传递
1 | SELECT multiSearchAllPositions('satori', ['sa', 'to', 'ri', 'xxx']); |
如果想大小写不敏感,那么可以使用 multiSearchAllPositionsCaseInsensitive。同样的,该函数也是在字节序列上进行搜索,不考虑字符编码,如果想支持非 ASCII 字符,应该使用 multiSearchAllPositionsUTF8。
match:正则表达式匹配,如果给定的字符串匹配给定的表达式,则返回 1;不匹配,则返回 0
1 | -- 字符串放左边,模式方右边 |
我们知道反斜杠本身代表转义,那么如果想表达 \d,应该使用 \d。同理如果我们想检测字符串是否包含反斜杠,那么应该这么做:
1 | SELECT match(s, '\\\\'); |
因为反斜杠具有转义,那么四个反斜杠会变成两个普通的反斜杠,但我们知道反斜杠在正则中也具有含义,所以两个反斜杠会变成一个普通的反斜杠。
multiMatchAny:正则表达式匹配,但可以接收多个模式,有一个能匹配上,则返回 1;全都匹配不上,则返回 0
1 | SELECT match('satori', 'xx'), match('satori', 'satori'); |
multiMatchAnyIndex:正则表达式匹配,接收多个模式,返回第一个匹配的模式的索引
1 | -- 显然 'satori' 可以匹配上,而它的索引为 3 |
如果没有一个能匹配上则返回 0,因为索引从 1 开始,所以返回 0 代表没有一个匹配上。像一般的编程语言,由于索引从 0 开始,那么当匹配不上的时候返回的就是 -1。
multiMatchAllIndices:正则表达式匹配,接收多个模式,返回所有匹配的模式的索引
1 | -- 索引为 2、3 的模式都能匹配上,但只返回第一个匹配上的 |
extract:返回使用正则表达式匹配的字符串
1 | -- 我们看到匹配使用的是贪婪模式 |
匹配不上,则返回空字符串。
extractAll:extract 只返回一个匹配的字符串,extractAll 则返回所有的
1 | SELECT extract('abc abd abe', 'ab.'), extractAll('abc abd abe', 'ab.'); |
extractAllGroupsHorizontal、extractAllGroupsVertical:匹配组,举例说明最直接
1 | SELECT extractAllGroupsHorizontal('2020-01-05 2020-02-21 2020-11-13', |
ClickHouse 在匹配组的时候也给了两种选择,我们在使用编程语言进行组匹配的时候,一般返回都是第二种。而且事实上,extractAllGroupsVertical 的速度比 extractAllGroupsHorizontal 要快一些。
当匹配不上的时候,返回的是空列表。
1 | SELECT extractAllGroupsHorizontal('2020-01-05 2020-02-21 2020-11-13', |
extractAllGroupsHorizontal 相当于把多个组中按照顺序合并了,所以列表里面是 3 个空列表,因为我们匹配的组有三个。
like:where 语句里面有 LIKE,但 like 也是一个函数,两者规则是一样的
1 | -- % 表示任意数量的任意字符;_ 表示单个任意字符 |
除了 like 之外,还有一个 notLike,以及不区分大小写的 ilike。
ngramDistance:计算两个字符串的相似度,取值为 0 到 1,越相似越接近 0
1 | SELECT ngramDistance('satori', 'satori') |
注意:如果某个字符串的长度超过了 32 KB,那么结果直接为 1,就不再计算相似度了。该函数在计算字符串相似度的时候是大小写敏感的,如果想要忽略大小写,可以使用 ngramDistanceCaseInsensitive。同理如果针对中文,那么可以使用 ngramDistanceUTF8,以及 ngramDistanceCaseInsensitiveUTF8。
countSubstrings:计算字符串中某个字串出现的次数
1 | SELECT countSubstrings('aaaa', 'aa'), countSubstrings('abc_abc', 'abc'); |
如果希望大小写敏感,那么可以使用 countSubstringsCaseInsensitive,针对中文可以使用 countSubstringsCaseInsensitiveUTF8。
countMatches:计算字符串中某个模式匹配的次数
1 | SELECT countSubstrings('aaabbaa', 'aa'), countMatches('aaabbaa', 'a.'); |
replaceOne:对字符串中指定的部分进行替换,但只会替换第一次出现的部分
1 | SELECT replaceOne('hello cruel world, cruel', 'cruel', 'beautiful'); |
如果想全部替换,那么可以使用 replaceAll:
1 | SELECT replaceAll('hello cruel world, cruel', 'cruel', 'beautiful'); |
replaceRegexpOne:对字符串中指定的部分进行替换,但支持正则
1 | SELECT replaceRegexpOne('hello cruel world, cruel', 'cru..', 'beautiful'); |
如果想全部替换,那么可以使用 replaceRegexpAll:
1 | SELECT replaceRegexpAll('hello cruel world, cruel', 'cru..', 'beautiful'); |
splitByChar:将字符串按照指定字符进行分解,返回数组
1 | -- 分隔符必须是单个字符 |
splitByString:将字符串按照指定字符(串)进行分解,返回数组
1 | -- 分隔符必须是单个字符 |
从这里可以看出 splitByString 完全可以取代 splitByChar,因为它既可以按照单个字符分解,也可以按照字符串分解,当然单个字符在 ClickHouse 里面也是字符串。但 ClickHouse 既然提供了两个函数,那么个人建议,如果是按照单个字符分解的话,还是使用 splitByChar。
splitByRegexp:将字符串按照正则的模式进行分解,返回数组
1 | SELECT splitByRegexp('\\d+', 'a12bc23de345f'); |
arrayStringConcat:将数组中的字符串进行拼接
1 | SELECT arrayStringConcat(['a', 'b', 'c', 'd'], '--'); |
小结
字符串算是非常常用的一个数据结构,它的操作自然也有很多,但都不是很难。