交叉表
交叉表(Cross Tabulations)是一种常用的分类汇总表格。使用交叉表查询,显示源于表中某个字段的汇总值,并将它们分组,其中一组列在数据表的左侧,另一组列在数据表的上部。行和列的交叉处可以对数据进行多种汇总计算,如:求和、平均值、记数、最大值、最小值等。使用交叉表查询数据非常直观明了,被广泛应用。交叉表查询也是数据库的一个特点。
例如:
select 表1.组名,
(select 表1.成员姓名 from 表2 b where 表1.成员1id=表2.成员id) as 成员1id,
(select 表1.成员姓名 from 表2 b where 表1.成员2id=表2.成员id) as 成员2id,
(select 表1.成员姓名 from 表2 b where 表1.成员3id=表2.成员id) as 成员3id
from 表1,表2
--这种就是交叉表查询
交叉报表是报表当中常见的类型,属于基本的报表,是行、列方向都有分组的报表。这里牵涉到另外一个概念即分组报表。这是所有报表当中最普通,最常见的报表类型,也是所有报表工具都支持的一种报表格式。从一般概念上来讲,分组报表就是只有纵向的分组。传统的分组报表制作方式是把报表划分为条带状,用户根据一个数据绑定向导指定分组,汇总字段,生成标准的分组报表。
这里我来演示下在POSTGRESQL里面如何实现交叉表的展示,下面话不多说了,来一起看看详细的介绍吧
原始表数据如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
t_girl=# select * from score; name | subject | score -------+---------+------- Lucy | English | 100 Lucy | Physics | 90 Lucy | Math | 85 Lily | English | 95 Lily | Physics | 81 Lily | Math | 84 David | English | 100 David | Physics | 86 David | Math | 89 Simon | English | 90 Simon | Physics | 76 Simon | Math | 79 (12 rows ) Time : 2.066 ms |
想要实现以下的结果:
1
2
3
4
5
6
|
name | English | Physics | Math ------+---------+---------+------ Simon | 90 | 76 | 79 Lucy | 100 | 90 | 85 Lily | 95 | 81 | 84 David | 100 | 86 | 89 |
大致有以下几种方法:
1、用标准SQL展现出来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
t_girl=# select name , t_girl-# sum ( case when subject = 'English' then score else 0 end ) as "English" , t_girl-# sum ( case when subject = 'Physics' then score else 0 end ) as "Physics" , t_girl-# sum ( case when subject = 'Math' then score else 0 end ) as "Math" t_girl-# from score t_girl-# group by name order by name desc ; name | English | Physics | Math -------+---------+---------+------ Simon | 90 | 76 | 79 Lucy | 100 | 90 | 85 Lily | 95 | 81 | 84 David | 100 | 86 | 89 (4 rows ) Time : 1.123 ms |
2、用PostgreSQL 提供的第三方扩展 tablefunc 带来的函数实现
以下函数crosstab 里面的SQL必须有三个字段,name, 分类以及分类值来作为起始参数,必须以name,分类值作为输出参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
t_girl=# SELECT * FROM crosstab( 'select name,subject,score from score order by name desc' ,$$ values ( 'English' ::text),( 'Physics' ::text),( 'Math' ::text)$$) AS score( name text, English int , Physics int , Math int ); name | english | physics | math -------+---------+---------+------ Simon | 90 | 76 | 79 Lucy | 100 | 90 | 85 Lily | 95 | 81 | 84 David | 100 | 86 | 89 (4 rows ) Time : 2.059 ms |
3、用PostgreSQL 自身的聚合函数实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
t_girl = # select name,split_part(split_part(tmp,',',1),':',2) as "English", t_girl - # split_part(split_part(tmp,',',2),':',2) as "Physics", t_girl - # split_part(split_part(tmp,',',3),':',2) as "Math" t_girl - # from t_girl - # ( t_girl( # select name,string_agg(subject||':'||score,',') as tmp from score group by name order by name desc t_girl( # ) as T; name | English | Physics | Math - - - - - - - + - - - - - - - - - + - - - - - - - - - + - - - - - - Simon | 90 | 76 | 79 Lucy | 100 | 90 | 85 Lily | 95 | 81 | 84 David | 100 | 86 | 89 ( 4 rows) Time: 2.396 ms |
4、 存储函数实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
create or replace function func_ytt_crosstab_py () returns setof ytt_crosstab as $ytt$ for row in plpy.cursor( "select name,string_agg(subject||':'||score,',') as tmp from score group by name order by name desc" ): a = row[ 'tmp' ].split( ',' ) yield (row[ 'name' ],a[ 0 ].split( ':' )[ 1 ],a[ 1 ].split( ':' )[ 1 ],a[ 2 ].split( ':' )[ 1 ]) $ytt$ language plpythonu; t_girl = # select name,english,physics,math from func_ytt_crosstab_py(); name | english | physics | math - - - - - - - + - - - - - - - - - + - - - - - - - - - + - - - - - - Simon | 90 | 76 | 79 Lucy | 100 | 90 | 85 Lily | 95 | 81 | 84 David | 100 | 86 | 89 ( 4 rows) Time: 2.687 ms |
5、 用PLPGSQL来实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
t_girl = # create type ytt_crosstab as (name text, English text, Physics text, Math text); CREATE TYPE Time: 22.518 ms create or replace function func_ytt_crosstab () returns setof ytt_crosstab as $ytt$ declare v_name text : = ''; v_english text : = ''; v_physics text : = ''; v_math text : = ''; v_tmp_result text : = ''; declare cs1 cursor for select name,string_agg(subject|| ':' ||score, ',' ) from score group by name order by name desc; begin open cs1; loop fetch cs1 into v_name,v_tmp_result; exit when not found; v_english = split_part(split_part(v_tmp_result, ',' , 1 ), ':' , 2 ); v_physics = split_part(split_part(v_tmp_result, ',' , 2 ), ':' , 2 ); v_math = split_part(split_part(v_tmp_result, ',' , 3 ), ':' , 2 ); return query select v_name,v_english,v_physics,v_math; end loop; end; $ytt$ language plpgsql; t_girl = # select name,English,Physics,Math from func_ytt_crosstab(); name | english | physics | math - - - - - - - + - - - - - - - - - + - - - - - - - - - + - - - - - - Simon | 90 | 76 | 79 Lucy | 100 | 90 | 85 Lily | 95 | 81 | 84 David | 100 | 86 | 89 ( 4 rows) Time: 2.127 ms |
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:https://blog.csdn.net/a258831020/article/details/48446213