clickhouse--行列转换

目录

  • 列转行
    • 数据准备
    • 数据需求
      • union all实现
      • arary join
  • 行转列
    • 数据准备
    • 数据需求
      • map
      • sumIf
  • 参考资料


列转行

数据准备

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

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

你可能感兴趣的:(clickhouse,大数据,大数据,clickhouse,sql)