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

交叉表

交叉表(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 

总结

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

(0)

相关推荐

  • PostgreSQL 创建表分区

    创建表分区步骤如下: 1. 创建主表 CREATE TABLE users ( uid int not null primary key, name varchar(20)); 2. 创建分区表(必须继承上面的主表) CREATE TABLE users_0 ( check (uid >= 0 and uid< 100) ) INHERITS (users); CREATE TABLE users_1 ( check (uid >= 100)) INHERITS (users); 3.

  • PostgreSQL新手入门教程

    自从MySQL被Oracle收购以后,PostgreSQL逐渐成为开源关系型数据库的首选. 本文介绍PostgreSQL的安装和基本用法,供初次使用者上手.以下内容基于Debian操作系统,其他操作系统实在没有精力兼顾,但是大部分内容应该普遍适用. 安装 1.首先,安装PostgreSQL客户端. sudo apt-get install postgresql-client 然后,安装PostgreSQL服务器. sudo apt-get install postgresql 2.正常情况下,安

  • PostgreSQL中的OID和XID 说明

    oid: 行的对象标识符(对象 ID).这个字段只有在创建表的时候使用了 WITH OIDS ,或者是设置了default_with_oids 配置参数时出现. 这个字段的类型是 oid (和字段同名). 例子: 复制代码 代码如下: CREATE TABLE pg_language ( lanname name NOT NULL, lanowner oid NOT NULL, lanispl boolean NOT NULL, lanpltrusted boolean NOT NULL, la

  • PostgreSQL 数据库性能提升的几个方面

    1.使用EXPLAIN EXPLAIN命令可以查看执行计划,在前面的blog中已经介绍过.这个方法是我们最主要的调试工具. 2.及时更新执行计划中使用的统计信息 由于统计 信息不是每次操作数据 库 都 进 行更新的,一般是在 VACUUM . ANALYZE . CREATE INDEX等DDL执行的时候会更新统计信息, 因此执 行 计 划所用的 统计 信息很有可能比 较 旧. 这样执 行 计 划的分析 结 果可能 误 差会 变 大. 以下是表tenk1的相关的一部分统计信息. SELECT r

  • PostgreSQL 安装和简单使用第1/2页

    据我了解国内四大国产数据库,其中三个都是基于PostgreSQL开发的.并且,因为许可证的灵活,任何人都可以以任何目的免费使用,修改,和分发 PostgreSQL,不管是私用,商用,还是学术研究使用.本文只是简单介绍一下postgresql的安装和简单的使用,语法方面涉及的比较少,以方便新手上路为目的. 1.系统环境和安装方法 : PostgreSQL的安装方法比较灵活,可以用源码包安装,也可以用您使用的发行版所带的软件包来安装,还可以采用在线安装-- 1.1 系统环境:Ubuntu Linux

  • Windows下PostgreSQL安装图解

    现在谈起免费数据库,大多数人首先想到的可能是MySQL,的确MySQL目前已经应用在国内很多领域,尤其是网站架设方面.但是,实际上功能最强大.特性最丰富和最复杂的免费数据库应该是PostgreSQL.它的很多特性正是当今许多商业数据库例如Oracle.DB2等的前身. 其实笔者最近也是因为项目需要,接触了一点PostgreSQL的皮毛,最近PostgreSQL又刚发布了8.1版本,笔者结合网上各位高手的经验谈一点自己的安装心得,和才开始接触PostgreSQL的新手朋友共同学习. 从Postgr

  • Windows PostgreSQL 安装图文教程

    它提供了多版本并行控制,支持几乎所有 SQL 构件(包括子查询,事务和用户定义类型和函数), 并且可以获得非常广阔范围的(开发)语言绑定 (包括 C,C++,Java,perl,tcl,和 python).本文介绍的是其在windows系统下的安装过程. 一般说来,一个现代的与 Unix 兼容的平台应该就能运行 PostgreSQL.而如果在windows系统下安装,你需要 Cygwin 和cygipc 包.另外,如果要制作服务器端编程语言 PL/Perl,则还需要完整的Perl安装,包括 li

  • 15个postgresql数据库实用命令分享

    最初是想找postgresql数据库占用空间命令发现的这篇blog,发现其中提供的几 条命令很有用(但也有几条感觉是充数的=.=),于是就把它翻译过来了.另外这篇文章是09年的,所以里面的内容可能有点过时,我收集了原文中有用的评论放在了最后面. 现在有不少开源软件都在使用postgreSQL作为它们的数据库系统.但公司可能不会招一些全职的postgreSQL DBA来维护它(piglei: 在国内基本也找不到).而会让一些比如说Oracle DBA.Linux系统管理员或者程序员去 维护.在这篇

  • Windows下Postgresql数据库的下载与配置方法

    注意下载的是二进制版,不是带Windows Installer的. http://www.enterprisedb.com/products-services-training/pgbindownload x86下载http://get.enterprisedb.com/postgresql/postgresql-9.2.4-1-windows-binaries.zip x64下载http://get.enterprisedb.com/postgresql/postgresql-9.2.4-1-

  • PostgreSQL 角色与用户管理介绍

    一.角色与用户的区别 角色就相当于岗位:角色可以是经理,助理.用户就是具体的人:比如陈XX经理,朱XX助理,王XX助理.在PostgreSQL 里没有区分用户和角色的概念,"CREATE USER" 为 "CREATE ROLE" 的别名,这两个命令几乎是完全相同的,唯一的区别是"CREATE USER" 命令创建的用户默认带有LOGIN属性,而"CREATE ROLE" 命令创建的用户默认不带LOGIN属性(CREATE U

随机推荐