PostgreSQL实现交叉表(行列转换)的5种方法示例

 更新时间:2020年7月11日 17:22  点击:2308

交叉表

交叉表(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里面如何实现交叉表的展示,下面话不多说了,来一起看看详细的介绍吧

原始表数据如下:

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 

想要实现以下的结果:

name | English | Physics | Math 
------+---------+---------+------ 
Simon |  90 |  76 | 79 
Lucy |  100 |  90 | 85 
Lily |  95 |  81 | 84 
David |  100 |  86 | 89 

大致有以下几种方法:

1、用标准SQL展现出来

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,分类值作为输出参数。

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 自身的聚合函数实现

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、 存储函数实现

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来实现

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 

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对猪先飞的支持。

[!--infotagslink--]

相关文章

  • PostgreSQL判断字符串是否包含目标字符串的多种方法

    这篇文章主要介绍了PostgreSQL判断字符串是否包含目标字符串的多种方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-23
  • PostgreSQL TIMESTAMP类型 时间戳操作

    这篇文章主要介绍了PostgreSQL TIMESTAMP类型 时间戳操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-26
  • postgresql 实现多表关联删除

    这篇文章主要介绍了postgresql 实现多表关联删除操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-02
  • Postgresql 如何选择正确的关闭模式

    这篇文章主要介绍了Postgresl 如何选择正确的关闭模式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-18
  • postgresql数据添加两个字段联合唯一的操作

    这篇文章主要介绍了postgresql数据添加两个字段联合唯一的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-04
  • PostgreSQL 字符串处理与日期处理操作

    这篇文章主要介绍了PostgreSQL 字符串处理与日期处理操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-01
  • postgresql重置序列起始值的操作

    这篇文章主要介绍了postgresql重置序列起始值,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-04
  • postgresql 中的时间处理小技巧(推荐)

    这篇文章主要介绍了postgresql 中的时间处理小技巧(推荐),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
  • PostgreSQL之分区表(partitioning)

    通过合理的设计,可以将选择一定的规则,将大表切分多个不重不漏的子表,这就是传说中的partitioning。比如,我们可以按时间切分,每天一张子表,比如我们可以按照某其他字段分割,总之了就是化整为零,提高查询的效能...2020-07-11
  • 基于postgresql数据库锁表问题的解决

    这篇文章主要介绍了基于postgresql数据库锁表问题的解决,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-30
  • 基于PostgreSQL和mysql数据类型对比兼容

    这篇文章主要介绍了基于PostgreSQL和mysql数据类型对比兼容,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-25
  • PostgreSQL 中的单引号与双引号用法说明

    这篇文章主要介绍了PostgreSQL 中的单引号与双引号用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-01
  • Postgresql数据库之创建和修改序列的操作

    这篇文章主要介绍了Postgresql数据库之创建和修改序列的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-04
  • postgresql影子用户实践场景分析

    这篇文章主要介绍了postgresql影子用户实践场景分析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-06
  • Postgresql中xlog生成和清理逻辑操作

    这篇文章主要介绍了Postgresql中xlog生成和清理逻辑操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-16
  • postgresql 利用xlog进行热备操作

    这篇文章主要介绍了postgresql 利用xlog进行热备操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-16
  • PostgreSQL 恢复误删数据的操作

    这篇文章主要介绍了PostgreSQL 恢复误删数据的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-18
  • 解决postgresql 自增id作为key重复的问题

    这篇文章主要介绍了解决postgresql 自增id作为key重复的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-04
  • PostgreSQL 实现定时job执行(pgAgent)

    这篇文章主要介绍了PostgreSQL 实现定时job执行(pgAgent),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-16
  • postgresql的jsonb数据查询和修改的方法

    这篇文章主要介绍了postgresql的jsonb数据查询和修改的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-03