clickhouse 类型错误、聚合函数错误——字段别名的注意事项

最近接触了clickhouse,不得不说性能是真的强大,即使最简单的使用,不加任何优化也比常规数据库要快上很多,所以一直把它当作普通数据库来用,也支持sql语句,上手起来很快,不过今天写需求时用到了case when语句,从而引出了clickhouse字段别名的一些用法。
首先说一下别名指的是:select columnA as columnB 这种用法。
(得出的结论均为自己摸索,未查到相关资料,如有错误多多指正)

最大不同:上一个字段的别名可在下面的字段中直接使用

这个是接触ck时最不习惯的问题,因为以前接触过的数据库没有过这种用法,所以在使用ck时遇到了很多错误。举例:
mysql数据库

mysql> select 1 as a ,a +1 as b;
ERROR 1054 (42S22): Unknown column 'a' in 'field list'

一个简单的查询,但是会报错,即上一个字段的别名是不能在接下来被识别的。
clickhouse:

SELECT
    1 AS a,
    a + 1 AS b

┌─a─┬─b─┐
│ 1 │ 2 │
└───┴───┘

1 rows in set. Elapsed: 0.004 sec.

但是在ck里,它是可以被识别的!!! 但是也会导致下面的字段中都会被强制替换。意思就如果表中原来有一个字段名是 “num” ,对其进行sum求和后,还是取了原来一样的别名 即:sum(num) as num
那接下来的字段是识别不到原来的num的,说的有点啰嗦,直接上测试:
建测试表:

CREATE TABLE test123
ENGINE = TinyLog() AS
SELECT
    'a' AS name,
    1 AS num
UNION ALL
SELECT
    'a' AS name,
    2 AS num
UNION ALL
SELECT
    'a' AS name,
    3 AS num
UNION ALL
SELECT
    'b' AS name,
    4 AS num

:) select * from test123 ;

┌─name─┬─num─┐
│ a    │   3 │
│ b    │   4 │
│ a    │   1 │
│ a    │   2 │
└──────┴─────┘

4 rows in set. Elapsed: 0.004 sec.

测试语句:

SELECT
    sum(num) AS num,
    sum(num + 1) AS num_1
FROM test123;

Received exception from server (version 20.12.3):
Code: 184. DB::Exception: Received from 10.***.***.***:9000. DB::Exception: Aggregate function sum(num) is found inside another aggregate function in query: While processing sum(num) AS num.

0 rows in set. Elapsed: 0.004 sec.

可以看到,这种写法在ck中会报错 Aggregate function sum(num) is found inside another aggregate,但是传统数据库是支持这种写法的,开始的时候不知道这个特性,
还以为是聚合函数的问题,看了半天聚合函数的文档。
但是一旦发现这个特性之后就会觉得它很实用!比如求占比的时候可以直接用算好的结果:
clickhouse 类型错误、聚合函数错误——字段别名的注意事项
而且虽然和传统数据库不一样,不过规避它的方式也很简单,只要取的别名不和原来字段名一样就好了。

SELECT
    sum(num) AS num1,
    sum(num + 1) AS num_1
FROM test123

┌─num1─┬─num_1─┐
│   10 │    14 │
└──────┴───────┘

1 rows in set. Elapsed: 0.004 sec.

但是很多时候为了美观(偷懒),就不想取新的名字,大多数时候也是没什么影响的,不过今天就遇到了问题,就是这个别名的识别不仅作用在select语句中,甚至

还作用在where语句中!

SELECT if(num > 1, '大于1', '小于1') AS num
FROM test123
WHERE num > 1

Received exception from server (version 20.12.3):
Code: 386. DB::Exception: Received from 10.***.***.***:9000. DB::Exception: There is no supertype for types String, UInt8 because some of them are String/FixedString and some of them are not: while executing 'FUNCTION greater(if(greater(num, 1), '大于1', '小于1') : 5, 1 : 1) -> greater(if(greater(num, 1), '大于1', '小于1'), 1) UInt8 : 6'.

0 rows in set. Elapsed: 0.004 sec.

就这么一个简单的类型错误:There is no supertype for types String, UInt8 because some of them are String/FixedString and some of them are not: while executing,排查了半天(当然也是遇到的错误的语句要比这个复杂,涉及到了case when的时间判断等,甚至在写这篇博客的时候我还以为是case when的问题。。。)
这么一来相当于直接顶替了传统数据库中having 的用法,所以各位如果也遇到了以上错误,可以注意下别名的问题,是不是有类似用法。

上一篇:Emit优化反射(属性的设置与获取)


下一篇:cocos2d-x 通过JNI实现c/c++和Android的java层函数交互