clickhouse 之 arrayJoin 函数、with子句以及 limit n by exp 的用法

本文介绍了ClickHouse数据库中的arrayJoin函数,它用于将数组展开为多行;with子句用于重用复杂的表达式,并可用于常量表达式、分组计算和标量查询;limit by函数则用于按特定字段分组并选取每个组的前n个记录。文中通过实例展示了这些功能的使用场景,包括留存率计算、数据分组和获取最新用户状态等。

clickhouse窗口函数

arrayJoin 函数

先把官方的文档贴上来。

这个函数是一个非常有用的函数。我们知道一般的函数不会去更改结果集的行数,只是计算每行的值。

对于聚合函数而言,他们将多行函数压缩到一行(fold 或者 reduce),而 arrayJoin 函数是将一行的结果展开到多行(unfold)。

需要说明的是:arrayJoin 函数中的参数是数组类型。

我们来看个例子:

SELECT arrayJoin([1,2,3] AS src) AS dst, "Hello", src;

分析,该结果有三列,第一列是将数组[1,2,3]展开到3行,第二列是Hello,第三列是src这个数组。所以最终查询到的结果是:

┌─dst─┬─\'Hello\'─┬─src─────┐
│   1 │ Hello     │ [1,2,3] │
│   2 │ Hello     │ [1,2,3] │
│   3 │ Hello     │ [1,2,3] │
└─────┴───────────┴─────────┘

再来看一个例子,下面的这个例子经常用于计算留存率。

SELECT  DISTINCT d,
        arrayJoin(array(d, d - 1, d - 3, d - 7)) dd,
        uid as uid2
FROM dws.dw_dau AS dau
prewhere d = yesterday() - 2;

分析:第二列的取值其实是给同一个d,同一个uid,分别取值 d, d-1, d-3 和 d-7。

结果:

'2020-11-10'| '2020-11-10'| 174411427
'2020-11-10'| '2020-11-09'| 174411427
'2020-11-10'| '2020-11-07'| 174411427
'2020-11-10'| '2020-11-03'| 174411427
'2020-11-10'| '2020-11-10'| 174411683
'2020-11-10'| '2020-11-09'| 174411683
'2020-11-10'| '2020-11-07'| 174411683
'2020-11-10'| '2020-11-03'| 174411683
'2020-11-10'| '2020-11-10'| 174413454
'2020-11-10'| '2020-11-09'| 174413454
'2020-11-10'| '2020-11-07'| 174413454
'2020-11-10'| '2020-11-03'| 174413454 

with 子句

with的功能还是很强大的,官方文档在这里。

with子句提供对公共表达式的支持,with子句的结果可以在select查询中被使用。

我们来看看它的用法。

  • with子句的结果可以是常量表达式
WITH '2019-08-01 15:23:00' as ts_upper_bound
SELECT *
FROM hits
WHERE
    EventDate = toDate(ts_upper_bound) 
AND
    EventTime <= ts_upper_bound
  • with子句的结果可以是 select子句中分组计算的结果。
WITH sum(bytes) as s
SELECT
    formatReadableSize(s),
    table
FROM system.parts
GROUP BY table
ORDER BY s
  • with子句的结果可以是标量自查询。
WITH
    (
        SELECT sum(bytes)
        FROM system.parts
        WHERE active
    ) AS total_disk_usage
SELECT
    (sum(bytes) / total_disk_usage) * 100 AS table_disk_usage,
    table
FROM system.parts
GROUP BY table
ORDER BY table_disk_usage DESC
LIMIT 10      

limit by 函数

官方文档先贴上来。

limit n by expression 表示选择第一个n每个不同值的行expression。就是按expression这个字段分组取每个分组里的前n个值。

举个简单的例子先直观的看一看:

假设有这样一个表 limit_by

id | val
1 | 10
1 | 11
1 | 12
2 | 20
2 | 21

我们做如下的查询:

SELECT * FROM limit_by ORDER BY id, val LIMIT 2 BY id

分析:对表先按照 id 排序,再按照 val 排序。然后取不同的id的前两行记录。得到的结果如下:

┌─id─┬─val─┐
│  110 │
│  111 │
│  220 │
│  221 │
└────┴─────┘

再做一个查询:

SELECT * FROM limit_by ORDER BY id, val LIMIT 1, 2 BY id

分析:这个查询语句和上面不同的地方在于limit 1,2 是从第2个记录开始取,取2个。得到的结果是:

┌─id─┬─val─┐
│  111 │
│  112 │
│  221 │
└────┴─────┘

我们看一个实际业务中遇到的例子:

该业务需求是:过去7天,每个用户的待处理请求的情况。ch代码如下:

SELECT uid2, uid
FROM
    (
     SELECT uid2, uid, id, accepted
     FROM mysqldump.contact_request
     WHERE toDate(uptime) >= yesterday()-7
     ORDER BY uptime DESC
     LIMIT 1 BY id
    )
WHERE accepted = 0

该ch代码中用到了 order by ... limit n by exp 先按时间降序排序,然后取时间最新的id对应的数据。

确保拿到的用户状态是最新的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值