clickhouse学习笔记(五)SQL操作

目录

一、增

二、删改

三、查询以及各种子句

1、with子句

 a、表达式为常量

b、表达式为函数调用

 c、表达式为子查询

2、from子句 

3、array join子句 

a、INNER ARRAY JOIN

b、LEFT ARRAY JOIN

c、数组的一些函数

groupArray

  groupUniqArray

arrayFlatten 

splitByChar 

arrayJoin 

arrayMap

 嵌套类型

4、 join子句

连接精度

 连接类型

注意事项

5、WHERE 与 PREWHERE 子句 

6,GROUP BY 子句

  WITH ROLLUP

WITH CUBE

WITH TOTALS

7、having子句

8、ORDER BY子句

NULLS LAST

NULLS FIRST

9、limit by  子句

10、 limit 子句

11、select和distinct子句 


一、增

 INSERT语句支持三种语法范式

第一种使用values格式

-- 中括号表示里面的内容可以省略
INSERT INTO [db.]table_name [(col1, col2, col3...)] VALUES (val1, val2, val3, ...), (val1, val2, val3, ...), ...

使用 VALUES 格式的语法写入数据时,还支持加入表达式或函数,例如:

INSERT INTO partizion_v2 VALUES('matsuri', toString(1+2), now())

第二种使用自定格式的语法:

INSERT INTO [db.]table_name [(col1, col2, col3...)] FORMAT format_name data_set

例子如下

INSERT INTO partition_v2 FORMAT CSV \'mea', 'www.mea.com', '2019-01-01''nana', 'www.nana.com', '2019-02-01''matsuri', 'www.matsuri.com', '2019-03-01'

第三种使用select子句形式的语法:

INSERT INTO [db.]table_name [(col1, col2, col3...)] SELECT ...

二、删改

ClickHouse 不是以事务为中心的数据库系统,它主要设计用于在线分析处理(OLAP)场景,强调的是高性能的读取和聚合查询,而不是复杂的事务处理。因此,ClickHouse 不支持传统意义上的 DELETE 和 UPDATE 操作,也不支持事务特性

然而,ClickHouse 提供了一种称为 Mutation 的机制,允许用户进行类似 DELETE 和 UPDATE 的操作。Mutation 语句的执行是一个异步的后台过程,语句被提交之后就会立即返回。所以这并不代表具体逻辑已经执行完毕,它的具体执行进度需要通过 system.mutations 系统表查询

Mutation 是通过 ALTER TABLE 语句实现的,使用方法例如:

DELETE 语句的完整语法如下所示:

ALTER TABLE [db_name.]table_name DELETE WHERE filter_expr
案例如下:删除id=xxx的
ALTER TABLE partition_v2 DELETE WHERE ID ='xxx'

UPDATE 支持在一条语句中同时定义多个修改字段,但是分区键和主键不能作为修改字段。修改语句如下:

ALTER TABLE [db_name.]table_name UPDATE column1 = expr1 [, ...] WHERE filter_expr

三、查询以及各种子句

注意:clickhouse对于sql语句的解析是大小写敏感的,ClickHouse 的类型也大小写敏感,比如:UInt8 不可以写成 uint8,String 不可以写成 string; 但关键字大小写不敏感,例如select a 和select A 意义不同,但是min max等大小写不敏感

1、with子句

格式为:with 表达式  as var   

作用就是增加可读性和可维护性

一个子句可以为多个表达式起名例如:WITH 1 AS a, 2 AS b SELECT a + b;

 a、表达式为常量

常量可以是整数,字符串,浮点数,甚至数组,都可以

使用方法例如:

with 10 as startselect number from system.numbers  where number>start limit 7
b、表达式为函数调用
WITH SUM(data_uncompressed_bytes) AS bytes
SELECT database, formatReadableSize(bytes) AS format
FROM system.columns
GROUP BY database
ORDER BY bytes DESC/*
┌─database─┬─format───┐
│ system   │ 5.32 GiB │
│ default  │ 0.00 B   │
└──────────┴──────────┘
*/

如果不使用 WITH 子句,那么 SELECT 里面出现的就是 formatReadableSize(SUM(data_uncompressed_bytes)),这样读起来不是很方便,所以使用 WITH 子句将里面的聚合函数调用起一个名字叫 bytes,那么后面的查询直接使用 bytes 即可。

 c、表达式为子查询

-- SELECT sum(data_uncompressed_bytes) FROM system.columns 会得到一个数值
-- 因此本质上和表达式为常量是类似的,只不过多了一个计算的过程
WITH (SELECT sum(data_uncompressed_bytes) FROM system.columns) AS total_bytes
SELECT database, (sum(data_uncompressed_bytes) / total_bytes) * 100 AS database_disk_usage
FROM system.columns
GROUP BY database
ORDER BY database_disk_usage DESC
/*
┌─database─┬─database_disk_usage─┐
│ system   │                 100 │
│ default  │                   0 │
└──────────┴─────────────────────┘
*/

注意表达式只能返回的数据不能超过 1 行,否则会抛出异常,且不可以放在from后面作为临时表使用,如果需要多个值可以放在一个容器(列表、集合、字典等等)里面

而postgresql是可以返回任何数据,行数不限,并且可以放在from后面当临时表,

与postgresql的命名也不同,clickhouse别名在as后面,postgresql在as前面

2、from子句 

from子句表示从何处读取数据,目前支持3种形式

从数据表中读取SELECT name FROM people从子查询中读取SELECT max_id FROM (SELECT max(id) AS max_id FROM people)从表函数中读取SELECT number FROM numbers(N) -- 会返回 0 到 N - 1

3、array join子句 

首先造一个包含array数组字段的测试表

CREATE TABLE t1 (title String,value Array(UInt8)
) ENGINE = Memory();-- 然后写入数据
INSERT INTO t1 VALUES ('food', [1, 2, 3]), ('fruit', [3, 4]), ('meat', []);-- 查询
SELECT * FROM t1;
/*
┌─title─┬─value───┐
│ food  │ [1,2,3] │
│ fruit │ [3,4]   │
│ meat  │ []      │
└───────┴─────────┘
*/

 在一条 SELECT 语句中,只能存在一个 ARRAY JOIN(使用子查询除外),目前支持 INNER 和 LEFT 两种 JOIN 策略:

a、INNER ARRAY JOIN

ARRAY JOIN 在默认情况下使用的是 INNER JOIN 策略,例如下面的语句:

SELECT title, value FROM t1 ARRAY JOIN value;
/*
┌─title─┬─value─┐
│ food  │     1 │
│ food  │     2 │
│ food  │     3 │
│ fruit │     3 │
│ fruit │     4 │
└───────┴───────┘
*/

从查询结果可以发现,最终的数据基于 value 数组被展开成了多行,并且排除掉了空数组,同时会自动和其它字段进行组合(相当于按行合并)。在使用 ARRAY JOIN 时,如果还想访问展开前的数组字段,那么只需为原有的数组字段添加一个别名即可,例如:

 -- 如果不给 ARRAY JOIN 后面的 value 起一个别名,那么 value 就是展开后的结果
-- 如果给 ARRAY JOIN 后面的 value 起一个别名 val,那么 value 就还是展开前的数组字段
-- 而 val 才是展开后的结果,所以再反过来,让 val 出现在 SELECT 中即可
SELECT title, value, val FROM t1 ARRAY JOIN value AS val;
/*
┌─title─┬─value───┬─val─┐
│ food  │ [1,2,3] │   1 │
│ food  │ [1,2,3] │   2 │
│ food  │ [1,2,3] │   3 │
│ fruit │ [3,4]   │   3 │
│ fruit │ [3,4]   │   4 │
└───────┴─────────┴─────┘
*/

 我们看到 ClickHouse 的确是当之无愧的最强 OLAP 数据库,不单单是速度快,最重要的是,它提供的查询语法也很方便。如果你用过 Hive 的话,会发现这里特别像里面的 lateral view explode 语法。

b、LEFT ARRAY JOIN

ARRAY JOIN 子句支持 LEFT 连接策略,例如执行下面的语句:

SELECT title, value, val FROM t1 LEFT ARRAY JOIN value AS val;
/*
┌─title─┬─value───┬─val─┐
│ food  │ [1,2,3] │   1 │
│ food  │ [1,2,3] │   2 │
│ food  │ [1,2,3] │   3 │
│ fruit │ [3,4]   │   3 │
│ fruit │ [3,4]   │   4 │
│ meat  │ []      │   0 │
└───────┴─────────┴─────┘
*/

在改为 LEFT 连接查询后,可以发现,在 INNER JOIN 中被排除掉的空数组出现在了返回的结果集中。但此时的 val 是零值。

c、数组的一些函数

有如下表

SELECT * FROM t2;
/*
┌─────────dt─┬─cash───────┐
│ 2020-01-01 │ [10,10,10] │
│ 2020-01-02 │ [20,20,20] │
│ 2020-01-01 │ [10,10,10] │
│ 2020-01-02 │ [20,20]    │
│ 2020-01-03 │ []         │
│ 2020-01-03 │ [30,30,30] │
└────────────┴────────────┘
*/

groupArray

它是把多行数据合并成一个数组,相当于是聚合函数的一种

SELECT dt, groupArray(cash) FROM t2 GROUP BY dt;
/*
┌─────────dt─┬─groupArray(cash)────────┐
│ 2020-01-01 │ [[10,10,10],[10,10,10]] │
│ 2020-01-02 │ [[20,20,20],[20,20]]    │
│ 2020-01-03 │ [[],[30,30,30]]         │
└────────────┴─────────────────────────┘
*/

  groupUniqArray

在组合的时候会对元素进行去重

SELECT dt, groupUniqArray(cash) FROM t2 GROUP BY dt;
/*
┌─────────dt─┬─groupUniqArray(cash)─┐
│ 2020-01-01 │ [[10,10,10]]         │
│ 2020-01-02 │ [[20,20],[20,20,20]] │
│ 2020-01-03 │ [[],[30,30,30]]      │
└────────────┴──────────────────────┘
*/

arrayFlatten 

类似于flatmap,将数组扁平化

SELECT dt, groupArray(cash),arrayFlatten(groupArray(cash)) FROM t2 GROUP BY dt;
SELECT dt, groupUniqArray(cash) FROM t2 GROUP BY dt;
/*
┌─────────dt─┬─groupUniqArray(cash)─┐─arrayFlatten(groupArray(cash))─┐
│ 2020-01-01 │ [[10,10,10],[10,10,10]]         │ [10,10,10,10,10,10]         │
│ 2020-01-02 │ [[20,20],[20,20,20]]             │ [20,2020,20,20]    │
│ 2020-01-03 │ [[],[30,30,30]]                  │ [30,30,30]         │
└────────────┴──────────────────────------------┘──────────────────────┘
*/

splitByChar 

将字符串按照指定字符分割成数组:

SELECT splitByChar('^', 'komeiji^koishi');
/*
┌─splitByChar('^', 'komeiji^koishi')─┐
│ ['komeiji','koishi']               │
└────────────────────────────────────┘
*/

arrayJoin 

该函数和 ARRAY JOIN 子句的作用非常类似:

 SELECT * FROM t1;
/*
┌─title─┬─value───┐
│ food  │ [1,2,3] │
│ fruit │ [3,4]   │
│ meat  │ []      │
└───────┴─────────┘
*/select title ,arrayjoin(value) from t1;/*
┌─title─┬─arrayjoin(value)─┐
│ food  │     1 │
│ food  │     2 │
│ food  │     3 │
│ fruit │     3 │
│ fruit │     4 │
└───────┴───────┘
*/

arrayMap

对数组中的每一个元素都以相同的规则进行映射:

-- arrayMap(x -> x * 2, value) 表示将 value 中的每一个元素都乘以 2,然后返回一个新数组
-- 而 mapV 就是变换过后的新数组,直接拿来用即可
SELECT title, arrayMap(x -> x * 2, value) AS mapV, v
FROM t1 LEFT ARRAY JOIN mapV as v
/*
┌─title─┬─mapV────┬─v─┐
│ food  │ [2,4,6] │ 2 │
│ food  │ [2,4,6] │ 4 │
│ food  │ [2,4,6] │ 6 │
│ fruit │ [6,8]   │ 6 │
│ fruit │ [6,8]   │ 8 │
│ meat  │ []      │ 0 │
└───────┴─────────┴───┘
*/-- 另外展开的字段也可以不止一个
SELECT title, arrayMap(x -> x * 2, value) AS mapV, v,value, v_1
FROM t1 LEFT ARRAY JOIN mapV as v, value AS v_1
/*
┌─title─┬─mapV────┬─v─┬─value───┬─v_1─┐
│ food  │ [2,4,6] │ 2 │ [1,2,3] │   1 │
│ food  │ [2,4,6] │ 4 │ [1,2,3] │   2 │
│ food  │ [2,4,6] │ 6 │ [1,2,3] │   3 │
│ fruit │ [6,8]   │ 6 │ [3,4]   │   3 │
│ fruit │ [6,8]   │ 8 │ [3,4]   │   4 │
│ meat  │ []      │ 0 │ []      │   0 │
└───────┴─────────┴───┴─────────┴─────┘
*/
 嵌套类型

在写入嵌套数据类型时,记得同一行数据中各个数组的长度需要对齐,而对多行数据之间的数组长度没有限制,否则会报错:如下

CREATE TABLE t3(title String,nested Nested(v1 UInt32,v2 UInt64)
) ENGINE = Log();-- 接着写入测试数据
-- 在写入嵌套数据类型时,记得同一行数据中各个数组的长度需要对齐,而对多行数据之间的数组长度没有限制
INSERT INTO t3
VALUES ('food', [1, 2, 3], [10, 20, 30]),('fruit', [4, 5], [40, 50]),('meat', [], [])
INSERT INTO t3
VALUES ('food', [1, 2, 3], [10, 20, 30,40]),('fruit', [4, 5], [40, 50]),('meat', [], [])当数组大小不同时如上,会报错,当然不同行的数组大小可以不同,例如food和fruit
SQL 错误 [190]: ClickHouse exception, code: 190, host: 192.168.81.15, port: 8123; Code: 190. DB::Exception: Elements 'nested.v1' and 'nested.v2' of Nested data structure 'nested' (Array columns) have different array sizes. (SIZES_OF_ARRAYS_DOESNT_MATCH) (version 22.1.3.7 (official build))

对嵌套类型数据的访问,ARRAY JOIN 既可以直接使用字段列名:

-- nested 只有 v1 和 v2
-- 所以 ARRAY JOIN nested.v1, nested.v2 等价于 ARRAY JOIN nested
SELECT title, nested.v1, nested.v2 FROM t3 ARRAY JOIN nested.v1, nested.v2
/*
┌─title─┬─nested.v1─┬─nested.v2─┐
│ food  │         1 │        10 │
│ food  │         2 │        20 │
│ food  │         3 │        30 │
│ fruit │         4 │        40 │
│ fruit │         5 │        50 │
└───────┴───────────┴───────────┘
*/

 嵌套类型也支持 ARRAY JOIN 部分嵌套字段,可以看到,在这种情形下,只有被 ARRAY JOIN 的数组才会展开。

SELECT title, nested.v1, nested.v2 FROM t3 ARRAY JOIN nested.v1
/*
┌─title─┬─nested.v1─┬─nested.v2──┐
│ food  │         1 │ [10,20,30] │
│ food  │         2 │ [10,20,30] │
│ food  │         3 │ [10,20,30] │
│ fruit │         4 │ [40,50]    │
│ fruit │         5 │ [40,50]    │
└───────┴───────────┴────────────┘
*/

 在查询嵌套类型时也能够通过别名的形式访问原始数组:

SELECT title, nested.v1, nested.v2, n.v1, n.v2  
from t3 ARRAY JOIN nested AS n;
/*
┌─title─┬─nested.v1─┬─nested.v2──┬─n.v1─┬─n.v2─┐
│ food  │ [1,2,3]   │ [10,20,30] │    1 │   10 │
│ food  │ [1,2,3]   │ [10,20,30] │    2 │   20 │
│ food  │ [1,2,3]   │ [10,20,30] │    3 │   30 │
│ fruit │ [4,5]     │ [40,50]    │    4 │   40 │
│ fruit │ [4,5]     │ [40,50]    │    5 │   50 │
└───────┴───────────┴────────────┴──────┴──────┘
*/

4、 join子句

JOIN 子句可以对左右两张表的数据进行连接,它的语法包含连接精度和连接类型两部分。

连接精度

连接精度决定了 JOIN 查询在连接数据时所使用的策略,目前支持 ALL、ANY 和 ASOF 三种类型(还有两种类型SEMI 和 ANTI只能用在left join和right join上面)。如果不主动声明,则默认是 ALL

举个例子有如下表数据:

SELECT * FROM tbl_1;
/*
┌─id─┬─code1─┬─count─┐
│  1 │ A001  │    30 │
│  2 │ A002  │    28 │
│  3 │ A003  │    32 │
└────┴───────┴───────┘
*/

SELECT * FROM tbl_2;
/*
┌─id─┬─code2─┬─count─┐
│  1 │ B001  │    35 │
│  1 │ B001  │    29 │
│  3 │ B003  │    31 │
│  4 │ B004  │    38 │
└────┴───────┴───────┘
*/

下面进行测试

SELECT t1.id, t1.code1, t2.code2 
FROM tbl_1 AS t1 
ALL INNER JOIN tbl_2 AS t2
ON t1.id = t2.id;
/*
┌─id─┬─code1─┬─code2─┐
│  1 │ A001  │ B001  │
│  1 │ A001  │ B001  │
│  3 │ A003  │ B003  │
└────┴───────┴───────┘
*/
-- 一切正常,跟一般的关系型数据库是类似的,但如果将 ALL 改成 ANY
SELECT t1.id, t1.code1, t2.code2 
FROM tbl_1 AS t1 
ANY INNER JOIN tbl_2 AS t2
ON t1.id = t2.id;
/*
┌─id─┬─code1─┬─code2─┐
│  1 │ A001  │ B001  │
│  3 │ A003  │ B003  │
└────┴───────┴───────┘
*/

除了 ALL 和 ANY 之外还有一个 ASOF,ALL 还是 ANY,在连接的时候必须是等值连接。但 ASOF 表示模糊连接,例如  t1.id >= t2.id 例子如下

SELECT t1.id, t1.code1, t2.code2, t1.count AS count1, t2.count AS count2
FROM tbl_1 AS t1 
ASOF INNER JOIN tbl_2 AS t2
ON t1.id = t2.id AND t1.count > t2.count;
/*
┌─id─┬─code1─┬─code2─┬─count1─┬─count2─┐
│  1 │ A001  │ B001  │     30 │     29 │
│  3 │ A003  │ B003  │     32 │     31 │
└────┴───────┴───────┴────────┴────────┘
*/

SEMI 和 ANTI

我们之前说连接精度不止 ALL、ANY、ASOF 三种,还有 SEMI 和 ANTI,只不过这两个比较特殊,因为它们只能用在 LEFT JOIN 和 RIGHT JOIN 上面,所以我们单独介绍。

  • t1 SEMI LEFT JOIN t2 USING(id):遍历 t1 中的 id,如果存在于 t2 中,则输出
  • t1 SEMI RIGHT JOIN t2 USING(id):遍历 t2 中的 id,如果存在于 t1 中,则输出
  • t1 ANTI LEFT JOIN t2 USING(id):遍历 t1 中的 id,如果不存在于 t2 中,则输出
  • t1 ANTI RIGHT JOIN t2 USING(id):遍历 t2 中的 id,如果不存在于 t1 中,则输出

这个 SEMI 的功能貌似有些重复了,因为我们使用 ALL 和 ANY 完全可以取代。其实如果你用过 hive 的话,会发现 SEMI LEFT JOIN 和 ANTI LEFT JOIN 是 IN/EXISTS 的一种更加高效的实现:

结论:

1,如果左表内的一行数据,在右表中有多行数据与之连接匹配,那么当连接精度为 ALL,会返回右表中全部连接的数据;

2,当连接精度为 ANY,会仅返回右表中第一行连接的数据

3,如果连接精度为 ASOF,那么允许在等值连接条件后面追加一个非等值连接,所以上面的 t1.id = t2.id 是等值连接,t1.count > t2.count 是非等值连接。但需要注意的是:使用非等值连接时,这个非等值可以是 >、>=、<、<=,但不能是 !=;并且对于 ASOF 而言,连接条件必须是等值连接和非等值连接的组合,两者缺一不可

 连接类型
-- 省略连接精度,默认为 ALL
-- 左连接
SELECT t1.id, t1.code1, t2.code2 
FROM tbl_1 t1 LEFT JOIN tbl_2 t2 
USING(id); -- 等价于 t1.id = t2.id
/*
┌─id─┬─code1─┬─code2─┐
│  1 │ A001  │ B001  │
│  1 │ A001  │ B001  │
│  2 │ A002  │       │
│  3 │ A003  │ B003  │
└────┴───────┴───────┘
*/-- 右连接
SELECT t1.id, t1.code1, t2.code2 
FROM tbl_1 t1 RIGHT JOIN tbl_2 t2 
USING(id);
/*
┌─id─┬─code1─┬─code2─┐
│  1 │ A001  │ B001  │
│  1 │ A001  │ B001  │
│  3 │ A003  │ B003  │
└────┴───────┴───────┘
┌─id─┬─code1─┬─code2─┐
│  4 │       │ B004  │
└────┴───────┴───────┘
*/-- 全连接
SELECT t1.id, t1.code1, t2.code2 
FROM tbl_1 t1 FULL JOIN tbl_2 t2 
USING(id);
/*
┌─id─┬─code1─┬─code2─┐
│  1 │ A001  │ B001  │
│  1 │ A001  │ B001  │
│  2 │ A002  │       │
│  3 │ A003  │ B003  │
└────┴───────┴───────┘
┌─id─┬─code1─┬─code2─┐
│  4 │       │ B004  │
└────┴───────┴───────┘
*/

和关系型数据库类似,但有一点区别,就是当没有与之匹配的记录时,会使用对应类型的空值进行补全,而不是 Null。这里没有指定连接精度,默认为 ALL

注意事项

最后,还有两个关于 JOIN 查询的注意事项。

1. 关于性能

        最后,还有两个关于 JOIN 查询的注意事项。为了能够优化 JOIN 查询性能,首先应该遵循左大右小的原则,即数据量小的表要放在右侧。这是因为在执行 JOIN 查询时,无论使用的是哪种连接方式,右表都会被全部加载到内存中与左表进行比较。

其次,JOIN 查询目前没有缓存的支持,这意味着每一次 JOIN 查询,即便是连续执行相同的 SQL,也都会生成一次全新的执行计划。如果应用程序会大量使用 JOIN 查询,则需要进一步考虑借助上层应用侧的缓存服务或使用 JOIN 表引擎来改善性能。

最后,如果是在大量维度属性补全的查询场景中,则建议使用字典代替 JOIN 查询。因为在进行多表的连接查询时,查询会转换成两两连接的形式,而这种滚雪球式的查询很可能带来性能问题。

2. 空值策略

        在之前的介绍中,连接查询的空值(那些未被连接的数据)是由默认值填充的,这与其他数据库所采取的策略不同(由Null 填充)。连接查询的空值策略通过 join_use_nulls 参数指定的,默认为 0。当参数值为 0 时,空值由数据类型的默认值填充;而当参数值为 1 时,空值由 Null 填充。

5、WHERE 与 PREWHERE 子句 

        除了 WHERE,ClickHouse 还支持全新的 PREWHERE 子句,PREWHERE 目前只能用于 MegeTee 系列的表引擎,它可以看作对是 WHERE 的一种优化,其作用与 WHERE 相同,均是用来过滤数据。但它们的不同之处在于。使用 PREWHERE 时,首先只会读取 PREWHERE 指定的列字段数据,用于数据过滤的条件判断。待数据过滤之后再读取 SELECT 声明的列字段以补全其余属性。所以在一些场合下,PREWHERE 相比 WHERE 而言,处理的数据量更少,性能更高。

既然 WHERE 子句性能更优,那么是否需要将所有的 WHERE 子句都替换成 PREWHERE 子句呢?其实大可不必,因为 ClickHouse 实现了自我优化的功能,会在条件合适的情况下将 WHERE 替换为 PREWHERE。如果想开启这项特性,只需要将 optimize_move_to_prewhere 设置为 1 即可,当然默认就为 1,即开启状态。

6,GROUP BY 子句

聚合查询能配合 WITH ROLLUP、WITH CUBE、WITH TOTALS 三种修饰符获取额外的汇总信息

造测试表

CREATE TABLE sales_data(product String,channel String,amount int) ENGINE = Log();-- 接着写入测试数据
INSERT INTO sales_data
VALUES ('桔子', '淘宝', 248175),('香蕉', '淘宝', 252148),('苹果', '店面', 246198),('香蕉', '店面', 256602),('桔子', '店面', 245029),('苹果', '淘宝', 252908),('苹果', '京东', 252057),('桔子', '京东', 251795),('香蕉', '京东', 245904)

  WITH ROLLUP

        GROUP BY 子句加上 WITH ROLLUP 选项时,首先按照全部的分组字段进行分组汇总;然后从右往左依次去掉一个分组字段再进行分组汇总,被去掉的字段显示为零值;最后,将所有的数据进行一次汇总,所有的分组字段都显示为零值。

select product,channel,sum(amount)
from  sales_data
group by product,channel 
with rollup查询结果如下桔子	淘宝	248175
香蕉	淘宝	252148
苹果	店面	246198
香蕉	店面	256602
桔子	店面	245029
苹果	淘宝	252908
苹果	京东	252057
桔子	京东	251795
香蕉	京东	245904
香蕉		    754654
桔子		    744999
苹果		    7511632250816

        我们注意到,多了四条数据,上面三条,就是按照 product、channel 汇总之后,再单独按 product 汇总,而此时会给对应的 channel 设为零值(这里是空字符串,关系型数据库中为 Null)。同理最后一条数据是全量汇总,不需要指定 product 和 channel,所以显示为 product 和 channel 都显示为零值。我们看到这就相当于按照 product 单独聚合然后再自动拼接在上面了,排好序,并且自动将 channel 赋值为零值,同理最后一条数据也是如此

WITH CUBE

        CUBE 代表立方体,它用于对分组字段进行各种可能的组合,能够产生多维度的交叉统计结果,CUBE 通常用于数据仓库中的交叉报表分析

select product,channel,sum(amount)
from  sales_data
group by product,channel 
with CUBE 桔子	淘宝	248175
香蕉	淘宝	252148
苹果	店面	246198
香蕉	店面	256602
桔子	店面	245029
苹果	淘宝	252908
苹果	京东	252057
桔子	京东	251795
香蕉	京东	245904
香蕉		    754654
桔子		    744999
苹果		    751163淘宝	753231京东	749756店面	7478292250816

        CUBE 返回了更多的分组数据,其中不仅包含了 ROLLUP 汇总的结果,还包含了相当于按照 channel 进行聚合的记录。因此随着分组字段的增加,CUBE 产生的组合将会呈指数级增长

WITH TOTALS

只包含一个全局汇总的结果

select product,channel,sum(amount)
from  sales_data
group by product,channel 
with TOTALS桔子	淘宝	248175
香蕉	淘宝	252148
苹果	店面	246198
香蕉	店面	256602
桔子	店面	245029
苹果	淘宝	252908
苹果	京东	252057
桔子	京东	251795
香蕉	京东	2459042250816

7、having子句

HAVING 子句要和 GROUP BY 子句同时出现,不能单独使用


select product,channel,sum(amount) as cnt 
from  sales_data
group by product,channel 
having  cnt>250000香蕉	淘宝	252148
香蕉	店面	256602
苹果	淘宝	252908
苹果	京东	252057
桔子	京东	251795

8、ORDER BY子句

        在 MergeTree 表引擎中也有 ORDER BY 参数用于指定排序键,这个的作用域是分区内,所以当查询时如果有多个分区就不保证顺序了,所以需要order by。在使用时可以定义多个排序键,每个排序键后需紧跟ASC 或者DESC,不写默认为asc

例如

SELECT * FROM tbl ORDER BY v1 ASC, v2 DESC;
SELECT * FROM tbl ORDER BY v1, v2 DESC;
NULLS LAST

null值排在最后,无论升序还是降序

写法如下

select arrayJoin([1,22,NULL,3,-1]) as v order by v asc-1
1
3
22
NULL
NULLS FIRST

null值排在第一,无论升序还是降序,写法如上

9、limit by  子句

        LIMIT BY 运行于 ORDER BY 之后和 LIMIT 之前,它能够按照指定分组,最多返回前 n 行数据(少于 n 行则按照实际数量返回),常用于 分组TOP N 的查询场景。LIMIT BY 语法规则如下:

表数据
香蕉	店面	256602
苹果	淘宝	252908
香蕉	淘宝	252148
苹果	京东	252057
桔子	京东	251795
桔子	淘宝	248175
苹果	店面	246198
香蕉	京东	245904
桔子	店面	245029

 

select product,channel,sum(amount) as cnt 
from  sales_data
group by product,channel 
order by cnt desc 
limit 1 by channel香蕉	店面	256602
苹果	淘宝	252908
苹果	京东	252057

LIMIT BY 也可以指定偏移量,因为不一定从一条开始选择,而指定偏移量有两种方式:

  • 一种方式如上:limit 条数  by  维度
  • 另一种方式:limit 条数,偏移量(从第几条开始)by 维度  案例如下
select product,channel,sum(amount) as cnt 
from  sales_data
group by product,channel 
order by cnt desc 
limit 1 ,1 by channel香蕉	淘宝	252148
桔子	京东	251795
苹果	店面	246198

10、 limit 子句

用法有三种如下

LIMIT N
LIMIT N OFFSET M
LIMIT M, N

limit 与limit by的区别

11、select和distinct子句 

支持正则查询,例如下面会选择以 n 开头和包含字母 p 的字段:

SELECT COLUMNS('^n'), COLUMNS('p') FROM system.databases

distinct和group by 执行后虽然结果相同,但是distinct的执行计划更简单,而且在不使用order  by子句时,distinct在limit n满足条件时立刻结束查询,后面的就不查了,group by会分组执行完后在limit 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/41862.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2005-2023年各省居民人均消费支出、城镇居民人均消费支出、农村居民人均消费支出数据(无缺失)

2005-2023年各省居民人均消费支出、城镇居民人均消费支出、农村居民人均消费支出数据&#xff08;无缺失&#xff09; 1、时间&#xff1a;2005-2023年 2、来源&#xff1a;国家统计局、统计年鉴 3、范围&#xff1a;31省 4、指标&#xff1a;全体居民人均消费支出、城镇居…

Windows netstat命令详解,Windows查看网络连接

「作者简介」&#xff1a;冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础著作 《网络安全自学教程》&#xff0c;适合基础薄弱的同学系统化的学习网络安全&#xff0c;用最短的时间掌握最核心的技术。 netstat 常用来…

rocketmq实现限流

目录 问题背景 技术方向 方案确认 消息队列&#xff08;√&#xff09; 分布式锁&#xff08;&#xff09; 方案实现 监控方向 业务方向 问题背景 公司邮件服务token有 分钟内超200封的熔断机制&#xff0c;当前token被熔断后&#xff0c;系统发邮件操作会被忽略&…

责任链模式(大话设计模式)C/C++版本

责任链模式 C #include <iostream> #include <memory>using namespace std; // 请求类 struct Request {std::string requestType; // 请求类型int number; // 该请求类型的数量std::string requestContent; // 请求内容 };// 抽象经理类 clas…

MySQL学习记录 —— 십칠 CentOS7.9环境下的MySQL8.4 安装和配置

文章目录 1、安装和配置2、MySQL 包位置3、主要程序介绍 本篇开始在之前mysql博客的基础上继续延伸&#xff0c;适合有一定基础的mysql使用者阅读 环境 &#xff1a;CentOS 7.9 root 用户&#xff0c;MySQL 8.4 1、安装和配置 看一下当前系统版本 cat /etc/redhat-release应当…

前端重点之:Vue+websocket通信详细用法和websocket心跳机制的使用,websocket断开实时监测,websocket实时通信

今年年初找工作,好多gou面试官总喜欢问关于websocket通信的使用方式,此次又用到了,在此做个总结:主要包含websocket的具体使用方法,和重点:(心跳机制的使用),就是主要是前端实时监测websocket是否有断连和数据的处理 在前端开发中,WebSocket 是一种常见的技术,用于…

众所周知沃尔玛1P是怎么运营?

​​沃尔玛的1P模式&#xff0c;即第一方供应商模式&#xff0c;是其独特的采购策略。在这种模式下&#xff0c;供应商先将商品卖给沃尔玛&#xff0c;由沃尔玛负责库存管理和销售。沃尔玛通过强大的采购和物流能力控制库存&#xff0c;确保商品品质&#xff0c;为客户提供更加…

FPGA问题

fpga 问题 第一道坎&#xff0c;安装软件&#xff1b;没有注册&#xff0c;无法产生sop文件&#xff0c;无法下载 没有相应的库的quartus ii版本&#xff0c;需要另下载 第二道坎&#xff0c;模拟器的下载&#xff0c;安装&#xff1b; 第三道&#xff0c;verilog 语法&#x…

deepspeed huggingface传入参数 optimizer和lr_scheduler测试

Trainer中 首先&#xff1a; WarmupDecayLR --lr_scheduler_type linear WarmupLR --lr_scheduler_type constant_with_warmup 1 TrainArgument不传lr_scheduler_type、optim&#xff0c;warmup_steps15 ds config文件中定义如下&#xff1a; 注意&#xff1a;如果不在Trai…

LangChain(四)工具调用的底层原理!给大模型按上双手吧!(新手向)

背景 经过前面三篇的内容&#xff0c;我想大家对于大模型的构建、Langchain的优势、Chain的构建有了相当程度的理解&#xff08;虽然只是最简单的示例&#xff0c;但是足够有代表性&#xff09;。 后续Chain的使用将会更加丰富多彩&#xff0c;您会了解Langchain开发的大模型…

14-31 剑和诗人5 - 使用 AirLLM 和分层推理在单个 4GB GPU 上运行 LLama 3 70B

利用分层推理实现大模型语言(LLM) 大型语言模型 (LLM) 领域最近取得了显著进展&#xff0c;LLaMa 3 70B 等模型突破了之前认为可能实现的极限。然而&#xff0c;这些模型的庞大规模给其部署和实际使用带来了巨大挑战&#xff0c;尤其是在资源受限的设备上&#xff0c;例如内存…

怎么压缩pdf文件的大小?减小PDF文件大小的四种方法

怎么压缩pdf文件的大小&#xff1f;文件大小不仅影响传输速度&#xff0c;还可能涉及存储空间的管理。当处理大型PDF文件时&#xff0c;可能会面临电子邮件附件限制或云存储容量不足的问题。此外&#xff0c;过大的文件在浏览和加载时也会导致延迟&#xff0c;影响阅读体验。这…

3款自己电脑就可以运行AI LLM的项目

AnythingLLM、LocalGPT和PrivateGPT都是与大语言模型&#xff08;LLM&#xff09;相关的项目&#xff0c;它们允许用户在本地环境中与文档进行交互&#xff0c;但它们在实现方式和特点上存在一些差异。AnythingLLM使用Pinecone和ChromaDB来处理矢量嵌入&#xff0c;并使用OpenA…

【C语言】return 关键字详解

在C语言中&#xff0c;return是一个关键字&#xff0c;用于从函数中返回值或者结束函数的执行。它是函数的重要组成部分&#xff0c;负责将函数的计算结果返回给调用者&#xff0c;并可以提前终止函数的执行。 主要用途和原理&#xff1a; 返回值给调用者&#xff1a; 当函数执…

【论文阅读】-- Visual Traffic Jam Analysis Based on Trajectory Data

基于轨迹数据的可视化交通拥堵分析 摘要1 引言2 相关工作2.1 交通事件检测2.2 交通可视化2.3 传播图可视化 3 概述3.1 设计要求3.2 输入数据说明3.3 交通拥堵数据模型3.4 工作流程 4 预处理4.1 路网处理4.2 GPS数据清理4.3 地图匹配4.4 道路速度计算4.5 交通拥堵检测4.6 传播图…

掌握【Python异常处理】:打造健壮代码的现代编程指南

目录 ​编辑 1. 什么是异常&#xff1f; 知识点 示例 小李的理解 2. 常见的内置异常类型 知识点 示例 小李的理解 3. 异常机制的意义 知识点 示例 小李的理解 4. 如何处理异常 知识点 示例 小李的理解 5. 抛出异常 知识点 示例 小李的理解 6. Python内置…

Springboot整合Jsch-Sftp

背景 开发一个基于jsch的sftp工具类&#xff0c;方便在以后的项目中使用。写代码的过程记录下来&#xff0c;作为备忘录。。。 Maven依赖 springboot依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-par…

codeforces 1633A

文章目录 1. 题目链接2. 题目代码正确代码错误代码 3. 题目总结 1. 题目链接 Div. 7 2. 题目代码 正确代码 #include<iostream> using namespace std; int main(){int testCase;cin >> testCase;while(testCase --){int ingeter;cin >> ingeter;if(!(inget…

SpringBoot彩蛋之定制启动画面

写在前面 在日常开发中&#xff0c;我们经常会看到各种各样的启动画面。例如以下几种 ① spring项目启动画面 ② mybatisplus启动画面 ③若依项目启动画面 还有很多各式各样好看的启动画面&#xff0c;那么怎么定制这些启动画面呢&#xff1f; 一、小试牛刀 ① 新建一个Spr…

SQL 之 concat_ws和concat的区别

concat_ws和concat都是用于连接字符串的函数&#xff0c;但它们在使用上有一些区别&#xff1a; 一、concat、concat_ws函数格式&#xff1a; concat格式&#xff1a; concat&#xff08;参数1,参数2,…参数n&#xff09;&#xff0c;如果要加’分隔符’直接写在 各参数中间就…