clickhouse--行列转换

本文详细介绍了如何在ClickHouse中通过unionall和arrayjoin实现数据的列转行操作,以及使用map和sumIf函数对数据进行按地区汇总。通过实例展示了如何从test_transfer表中按pkg分组,分别统计每个地区的数值并转化为行格式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


列转行

数据准备

创建一张数据表,如下所示:

create table test.test_transfer(
	pkg String,
	day String,
	region_0 UInt32,
	region_1 UInt32,
	region_2 UInt32
) ENGINE = MergeTree()
partition by day
ORDER BY pkg

插入数据:

INSERT INTO test.test_transfer VALUES
('pkg1', '20220510', 1000, 2000, 3000),
('pkg1', '20220511', 1000, 2000, 3000),
('pkg1', '20220512', 1000, 2000, 3000),
('pkg1', '20220513', 1000, 2000, 3000),
('pkg1', '20220411', 1000, 2000, 3000),
('pkg1', '20220412', 1000, 2000, 3000),
('pkg2', '20220510', 1000, 2000, 3000),
('pkg2', '20220511', 2000, 3000, 3000),
('pkg2', '20220512', 1000, 3000, 3000),
('pkg2', '20220513', 3000, 2000, 3000)

查询结果可以得到:

SELECT *
FROM test.test_transfer
FORMAT PrettyCompactMonoBlock
┌─pkg──┬─day──────┬─region_0─┬─region_1─┬─region_2─┐
│ pkg1 │ 20220513 │     1000 │     2000 │     3000 │
│ pkg2 │ 20220513 │     3000 │     2000 │     3000 │
│ pkg1 │ 20220412 │     1000 │     2000 │     3000 │
│ pkg1 │ 20220512 │     1000 │     2000 │     3000 │
│ pkg2 │ 20220512 │     1000 │     3000 │     3000 │
│ pkg1 │ 20220510 │     1000 │     2000 │     3000 │
│ pkg2 │ 20220510 │     1000 │     2000 │     3000 │
│ pkg1 │ 20220411 │     1000 │     2000 │     3000 │
│ pkg1 │ 20220511 │     1000 │     2000 │     3000 │
│ pkg2 │ 20220511 │     2000 │     3000 │     3000 │
└──────┴──────────┴──────────┴──────────┴──────────┘

数据需求

需要按照pkg列求其按照不同区间的数值。

union all实现

select 
	pkg,
	'region0' as region,
	sum(region_0) as value
from test.test_transfer
group by pkg
union all
select 
	pkg,
	'region1' as region,
	sum(region_1) as value
from test.test_transfer
group by pkg
union all
select 
	pkg,
	'region2' as region,
	sum(region_2) as value
from test.test_transfer
group by pkg
FORMAT PrettyCompactMonoBlock;

结果如下:

┌─pkg──┬─region──┬─value─┐
│ pkg1 │ region0 │  6000 │
│ pkg2 │ region0 │  7000 │
│ pkg1 │ region2 │ 18000 │
│ pkg2 │ region2 │ 12000 │
│ pkg1 │ region1 │ 12000 │
│ pkg2 │ region1 │ 10000 │
└──────┴─────────┴───────┘

arary join

采用这种方式话,首先我们要将每个区间的统计值算出来,然后将不同区间结果压缩得到一个数组,代码如下:

select
	pkg,
	array(region_0, region_1, region_2) as value_arr
from
	(select 
		pkg,
		sum(region_0) as region_0,
		sum(region_1) as region_1,
		sum(region_2) as region_2
	from test.test_transfer
	group by pkg
	) aa
FORMAT PrettyCompactMonoBlock;

查询的结果如下:

┌─pkg──┬─value_arr──────────┐
│ pkg1 │ [6000,12000,18000] │
│ pkg2 │ [7000,10000,12000] │
└──────┴────────────────────┘

那么得到数组之后呢,我们就可以使用array join的方法对数组进行展开了,代码如下:

select
	pkg,
	region,
	value
from
	(select
		pkg,
		array(region_0, region_1, region_2) as value_arr
	from
		(select 
			pkg,
			sum(region_0) as region_0,
			sum(region_1) as region_1,
			sum(region_2) as region_2
		from test.test_transfer
		group by pkg
		) aa
	) bb
array join
	['region_0', 'region_1', 'region_2'] as region,
	value_arr as value
FORMAT PrettyCompactMonoBlock;

得到结果如下:

┌─pkg──┬─region───┬─value─┐
│ pkg1 │ region_0 │  6000 │
│ pkg1 │ region_1 │ 12000 │
│ pkg1 │ region_2 │ 18000 │
│ pkg2 │ region_0 │  7000 │
│ pkg2 │ region_1 │ 10000 │
│ pkg2 │ region_2 │ 12000 │
└──────┴──────────┴───────┘

行转列

数据准备

创建一张数据表,如下所示:

create table test.test_transfer2(
	pkg String,
	region String,
	value UInt32
) ENGINE = MergeTree()
ORDER BY pkg

插入数据:

INSERT INTO test.test_transfer2 VALUES
('pkg1', 'region_0', 3000),
('pkg1', 'region_0', 3000),
('pkg1', 'region_1', 12000),
('pkg1', 'region_2', 8000),
('pkg1', 'region_2', 6000),
('pkg1', 'region_2', 4000),
('pkg2', 'region_0', 7000),
('pkg2', 'region_1', 10000),
('pkg2', 'region_2', 12000)

查询结果可以得到:

SELECT *
FROM test.test_transfer2
┌─pkg──┬─region───┬─value─┐
│ pkg1 │ region_0 │  3000 │
│ pkg1 │ region_0 │  3000 │
│ pkg1 │ region_1 │ 12000 │
│ pkg1 │ region_2 │  8000 │
│ pkg1 │ region_2 │  6000 │
│ pkg1 │ region_2 │  4000 │
│ pkg2 │ region_0 │  7000 │
│ pkg2 │ region_1 │ 10000 │
│ pkg2 │ region_2 │ 12000 │
└──────┴──────────┴───────┘

数据需求

将region列的数据按照值转为不同的列,并将对应的value值统计之后填进去。

map

clickhouse中的map方法可以实现类似pivot的功能,如下所示:

WITH CAST(sumMap([region], [value]), 'Map(String, UInt32)') AS map
select 
	pkg,
	map['region_0'] AS region_0,
    map['region_1'] AS region_1,
    map['region_2'] AS region_2
from test.test_transfer2
group by pkg

结果如下所示:

┌─pkg──┬─region_0─┬─region_1─┬─region_2─┐
│ pkg1 │     6000 │    12000 │    18000 │
│ pkg2 │     7000 │    10000 │    12000 │
└──────┴──────────┴──────────┴──────────┘

sumIf

也可以使用clickhouse中的sumIf函数进行条件求和,并命名为指定的列,如下:

select
	pkg,
	sumIf(value, region = 'region_0') AS region_0, 
    sumIf(value, region = 'region_1') AS region_1, 
    sumIf(value, region = 'region_2') AS region_2
from test.test_transfer2
group by pkg

结果如下:

┌─pkg──┬─region_0─┬─region_1─┬─region_2─┐
│ pkg1 │     6000 │    12000 │    18000 │
│ pkg2 │     7000 │    10000 │    12000 │
└──────┴──────────┴──────────┴──────────┘

参考资料

如何在 ClickHouse 中实现行列转换
clickhouse pivot / unpivot

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值