1. 程式人生 > 資料庫 >PostgreSQL實現交叉表(行列轉換)的5種方法示例

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",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,') 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,') 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,2); 
 v_physics = split_part(split_part(v_tmp_result,2); 
 v_math = split_part(split_part(v_tmp_result,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 

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對我們的支援。