当前位置: 代码迷 >> 综合 >> ClickHouse-SQL练习一
  详细解决方案

ClickHouse-SQL练习一

热度:16   发布时间:2024-01-13 16:12:09.0

一、需求

表一经过sql语句输出为表二

-- 表一:
─uid─┬─gender─┬─agegroup─┬─favor─┐
│   1 │ M      │ 90后     │ sm    │
│   2 │ M      │ 70后     │ sj    │
│   3 │ M      │ 90后     │ ms    │
│   4 │ F      │ 80后     │ sj    │
│   5 │ F      │ 90后     │ ms    │
└─────┴────────┴──────────┴───────┘-- 表二:
┌─tag──────┬─tag_value─┬─uid─────┐
│ agegroup │ 70后      │ [2]     │
│ agegroup │ 80后      │ [4]     │
│ agegroup │ 90后      │ [1,3,5] │
│ favor    │ ms        │ [3,5]   │
│ favor    │ sj        │ [2,4]   │
│ favor    │ sm        │ [1]     │
│ gender   │ F         │ [4,5]   │
│ gender   │ M         │ [1,2,3] │
└──────────┴───────────┴─────────┘

二、分析

表一到表二是一眼看不出来的,可以一步一步来,用反推来

1、uid展开(列转行)

列转行:将一列中复杂的array或者map结构拆分成多行

把表二的uid展开如下

标签 标签值 用户
年龄段 90后 1
年龄段 90后 3
年龄段 90后 5
年龄段 80后 4
年龄段 70后 2
性别 1
性别 2
性别 3
性别 4
性别 5
偏好 数码 1
偏好 美食 3
偏好 美食 5
偏好 书籍 2
偏好 书籍 4

排序看起来可能更好理解

标签 标签值 用户
年龄段 90后 1
性别 1
偏好 数码 1
年龄段 70后 2
性别 2
偏好 书籍 2
年龄段 90后 3
性别 3
偏好 美食 3
年龄段 80后 4
性别 4
偏好 书籍 4
年龄段 90后 5
性别 5
偏好 美食 5

2、聚合

统计每个uid,聚合起来如下

用户 标签值
1 [(年龄段,90后),(性别,男),(偏好,数码)]
2 [(年龄段,70后),(性别,男),(偏好,书籍)]
3 [(年龄段,90后),(性别,男),(偏好,美食)]
4 [(年龄段,80后),(性别,女),(偏好,书籍)]
5 [(年龄段,90后),(性别,女),(偏好,美食)]

三、结果步骤

1、查询

查询出数据

select
agegroup,
gender,
favor,
uid
from user_tag_merge
;┌─agegroup─┬─gender─┬─favor─┬─uid─┐
│ 90后     │ M      │ sm    │   1 │
│ 70后     │ M      │ sj    │   2 │
│ 90后     │ M      │ ms    │   3 │
│ 80后     │ F      │ sj    │   4 │
│ 90后     │ F      │ ms    │   5 │
└──────────┴────────┴───────┴─────┘

2、组合成元组

每个值前面,补上字段名,用**()组合成元组**

select
('agegroup', agegroup ), ('gender',gender ),('favor',favor ),uid 
from user_tag_merge
;┌─tuple('agegroup', agegroup)─┬─tuple('gender', gender)─┬─tuple('favor', favor)─┬─uid─┐
│ ('agegroup','90后')('gender','M')('favor','sm')1 │
│ ('agegroup','70后')('gender','M')('favor','sj')2 │
│ ('agegroup','90后')('gender','M')('favor','ms')3 │
│ ('agegroup','80后')('gender','F')('favor','sj')4 │
│ ('agegroup','90后')('gender','F')('favor','ms')5 │
└─────────────────────────────┴─────────────────────────┴───────────────────────┴─────┘

3、拼接成数组

在clickhouse中直接用[]来表示数组

select
[('agegroup', agegroup  ),('gender',gender ),('favor',favor )]  tag_code_value,uid 
from user_tag_merge
;┌─tag_code_value──────────────────────────────────────┬─uid─┐
│ [('agegroup','90后'),('gender','M'),('favor','sm')]1 │
│ [('agegroup','70后'),('gender','M'),('favor','sj')]2 │
│ [('agegroup','90后'),('gender','M'),('favor','ms')]3 │
│ [('agegroup','80后'),('gender','F'),('favor','sj')]4 │
│ [('agegroup','90后'),('gender','F'),('favor','ms')]5 │
└─────────────────────────────────────────────────────┴─────┘

4、炸开

arrayJoin炸开,类似于hive中的explode

SELECT
arrayJoin
([('agegroup', agegroup), ('gender', gender), ('favor', favor)])
AS tag_code_value,uid
FROM user_tag_merge
;┌─tag_code_value──────┬─uid─┐
│ ('agegroup','90后')1 │
│ ('gender','M')1 │
│ ('favor','sm')1 │
│ ('agegroup','70后')2 │
│ ('gender','M')2 │
│ ('favor','sj')2 │
│ ('agegroup','90后')3 │
│ ('gender','M')3 │
│ ('favor','ms')3 │
│ ('agegroup','80后')4 │
│ ('gender','F')4 │
│ ('favor','sj')4 │
│ ('agegroup','90后')5 │
│ ('gender','F')5 │
│ ('favor','ms')5 │
└─────────────────────┴─────┘

5、拆分

把元组中的字段名和字段值拆开

SELECT
tag_code_value.1 AS tag_code,
tag_code_value.2 AS tag_value,
uid
FROM 
(
SELECT
arrayJoin([('agegroup', agegroup), ('gender', gender), ('favor', favor)])
AS tag_code_value, uid   
FROM user_tag_merge
) AS tv
;┌─tag_code─┬─tag_value─┬─uid─┐
│ agegroup │ 90后      │   1 │
│ gender   │ M         │   1 │
│ favor    │ sm        │   1 │
│ agegroup │ 70后      │   2 │
│ gender   │ M         │   2 │
│ favor    │ sj        │   2 │
│ agegroup │ 90后      │   3 │
│ gender   │ M         │   3 │
│ favor    │ ms        │   3 │
│ agegroup │ 80后      │   4 │
│ gender   │ F         │   4 │
│ favor    │ sj        │   4 │
│ agegroup │ 90后      │   5 │
│ gender   │ F         │   5 │
│ favor    │ ms        │   5 │
└──────────┴───────────┴─────┘

6、聚合

用前两个字段作为维度聚合uid

SELECT
tag_code_value.1 AS tag_code,
tag_code_value.2 AS tag_value,
groupArray(uid) as us
FROM 
(
SELECT
arrayJoin([('agegroup', agegroup), ('gender', gender), ('favor', favor)])
AS tag_code_value, uid   
FROM user_tag_merge
) AS tv
group by
tag_code_value.1,
tag_code_value.2
;┌─tag_code─┬─tag_value─┬─us──────┐
│ gender   │ F         │ [4,5]   │
│ agegroup │ 70后      │ [2]     │
│ agegroup │ 90后      │ [1,3,5] │
│ agegroup │ 80后      │ [4]     │
│ gender   │ M         │ [1,2,3] │
│ favor    │ ms        │ [3,5]   │
│ favor    │ sj        │ [2,4]   │
│ favor    │ sm        │ [1]     │
└──────────┴───────────┴─────────┘

四、扩展-转换为Bitmap表

在最后一步上把groupArray 替换成groupBitmapState

SELECT
tag_code_value.1 AS tag_code,
tag_code_value.2 AS tag_value,
groupBitmapState(uid) as us
FROM 
(
SELECT
arrayJoin([('agegroup', agegroup), ('gender', gender), ('favor', favor)])
AS tag_code_value, uid   
FROM user_tag_merge
) AS tv
group by
tag_code_value.1,
tag_code_value.2
;┌─tag_code─┬─tag_value─┬─us─┐
│ gender   │ F         │    │
│ agegroup │ 70后      │    │
│ agegroup │ 90后      │    │
│ agegroup │ 80后      │    │
│ gender   │ M         │    │
│ favor    │ ms        │    │
│ favor    │ sj        │    │
│ favor    │ sm        │    │
└──────────┴───────────┴────┘

注意:这里聚合成bitmap的列没有显示是正常的,因为bitmap的结构本身无法用正常文本显示

  相关解决方案