PG中的行转列示例

Posted chuangsi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PG中的行转列示例相关的知识,希望对你有一定的参考价值。

简介

PG有三种行转列写法:

1、group by + sum + case when

2、用postgresql的crosstab函数

3、group by + string_agg + split_part(分组,行转列,字符切割)

环境准备

  1. CREATE TABLE sales (

  2. year INTEGER,

  3. quarter INTEGER,

  4. sales_amount NUMERIC

  5. );

  6.  

  7. INSERT INTO sales VALUES

  8. (2018, 1, 100),

  9. (2018, 2, 200),

  10. (2018, 3, 300),

  11. (2018, 4, 400),

  12. (2019, 1, 500),

  13. (2019, 2, 600),

  14. (2019, 3, 700),

  15. (2019, 4, 800);

我们想将每个季度的销售额作为一列,年份作为行,结果:

  1. year | q1 | q2 | q3 | q4

  2. ------+-----+-----+-----+-----

  3. 2018 | 100 | 200 | 300 | 400

  4. 2019 | 500 | 600 | 700 | 800

  5. (2 rows)

方法1:使用crosstab函数

PostgreSQL中可以使用crosstab函数将行转列,需要使用一个额外的模块“tablefunc”,安装完成后,我们可以使用crosstab函数将行转列。

  1. CREATE EXTENSION tablefunc;

  2.  

  3. SELECT *

  4. FROM crosstab(

  5. \'SELECT year, quarter, sales_amount

  6. FROM sales

  7. ORDER BY 1, 2\',

  8. \'SELECT quarter FROM generate_series(1,4) AS quarter\'

  9. ) AS sales_pivot(year INTEGER, q1 NUMERIC, q2 NUMERIC, q3 NUMERIC, q4 NUMERIC);

在这个例子中,我们将查询作为第一个参数传递给crosstab函数。查询必须按年份和季度排序。第二个参数是一个子查询,用于生成列名。在本例中,我们使用generate_series函数生成1到4之间的数字作为季度列的名称。

crosstab函数将行转换为列,并返回一个新的表。我们在外部查询中指定每个生成的列的数据类型和名称,以便正确返回结果。

方法2:使用group by + sum + case when

使用GROUP BY + SUM + CASE WHEN 也可以实现将行转列的效果。以下是一个示例:

  1. SELECT

  2. year,

  3. SUM(CASE WHEN quarter = 1 THEN sales_amount ELSE 0 END) AS q1,

  4. SUM(CASE WHEN quarter = 2 THEN sales_amount ELSE 0 END) AS q2,

  5. SUM(CASE WHEN quarter = 3 THEN sales_amount ELSE 0 END) AS q3,

  6. SUM(CASE WHEN quarter = 4 THEN sales_amount ELSE 0 END) AS q4

  7. FROM sales

  8. GROUP BY year

  9. ORDER BY year;

在这个示例中,我们使用了四个不同的CASE WHEN表达式来计算每个季度的销售额。在每个CASE WHEN表达式中,我们检查季度是否等于1、2、3或4,如果是,就将对应的销售额加入到该季度的总计中。否则,我们将0加入到总计中。

在查询中,我们使用GROUP BY子句对年份进行分组,并对每个季度的销售额进行求和。结果与使用crosstab函数得到的结果相同。

方法3:使用group by + string_agg + split_part(分组,行转列,字符切割)

使用GROUP BY + string_agg + split_part 也可以实现将行转列的效果。以下是一个示例:

  1. SELECT

  2. year,

  3. split_part(sales_agg, \',\', 1)::numeric AS q1,

  4. split_part(sales_agg, \',\', 2)::numeric AS q2,

  5. split_part(sales_agg, \',\', 3)::numeric AS q3,

  6. split_part(sales_agg, \',\', 4)::numeric AS q4

  7. FROM (

  8. SELECT

  9. year,

  10. string_agg(sales_amount::text, \',\' ORDER BY quarter) AS sales_agg

  11. FROM sales

  12. GROUP BY year

  13. ) AS sales_pivot;

在这个示例中,我们使用string_agg函数将每个季度的销售额连接成一个以逗号分隔的字符串(这里一定需要加上order by子句)。然后,我们使用split_part函数将字符串拆分成四个部分,以获取每个季度的销售额,并将其转换为数字类型。最后,我们在外部查询中指定了每个季度的数据类型和名称。

在查询中,我们首先使用GROUP BY子句对年份进行分组,并使用string_agg函数将每个季度的销售额连接成一个以逗号分隔的字符串。然后,我们在外部查询中使用split_part函数将字符串拆分成四个部分,并将其转换为数字类型,以获取每个季度的销售额。结果与使用crosstab函数或GROUP BY + SUM + CASE WHEN得到的结果相同。

 

sql的行转列(PIVOT)与列转行(UNPIVOT)

在做数据统计的时候,行转列,列转行是经常碰到的问题。case when方式太麻烦了,而且可扩展性不强,可以使用 PIVOT,UNPIVOT比较快速实现行转列,列转行,而且可扩展性强

一、行转列

1、测试数据准备

CREATE  TABLE [StudentScores]
(
   [UserName]         NVARCHAR(20),        --学生姓名
   [Subject]          NVARCHAR(30),        --科目
   [Score]            FLOAT,               --成绩
)

INSERT INTO [StudentScores] SELECT \'张三\', \'语文\', 80
INSERT INTO [StudentScores] SELECT \'张三\', \'数学\', 90
INSERT INTO [StudentScores] SELECT \'张三\', \'英语\', 70
INSERT INTO [StudentScores] SELECT \'张三\', \'生物\', 85
INSERT INTO [StudentScores] SELECT \'李四\', \'语文\', 80
INSERT INTO [StudentScores] SELECT \'李四\', \'数学\', 92
INSERT INTO [StudentScores] SELECT \'李四\', \'英语\', 76
INSERT INTO [StudentScores] SELECT \'李四\', \'生物\', 88
INSERT INTO [StudentScores] SELECT \'码农\', \'语文\', 60
INSERT INTO [StudentScores] SELECT \'码农\', \'数学\', 82
INSERT INTO [StudentScores] SELECT \'码农\', \'英语\', 96
INSERT INTO [StudentScores] SELECT \'码农\', \'生物\', 78

2、行转列sql

SELECT * FROM [StudentScores] /*数据源*/
AS P
PIVOT 
(
    SUM(Score/*行转列后 列的值*/) FOR 
    p.Subject/*需要行转列的列*/ IN ([语文],[数学],[英语],[生物]/*列的值*/)
) AS T

执行结果:

二、列转行

1、测试数据准备

CREATE TABLE ProgrectDetail
(
    ProgrectName         NVARCHAR(20), --工程名称
    OverseaSupply        INT,          --海外供应商供给数量
    NativeSupply         INT,          --国内供应商供给数量
    SouthSupply          INT,          --南方供应商供给数量
    NorthSupply          INT           --北方供应商供给数量
)

INSERT INTO ProgrectDetail
SELECT \'A\', 100, 200, 50, 50
UNION ALL
SELECT \'B\', 200, 300, 150, 150
UNION ALL
SELECT \'C\', 159, 400, 20, 320
UNION ALL

2、列转行的sql

SELECT P.ProgrectName,P.Supplier,P.SupplyNum
FROM 
(
    SELECT ProgrectName, OverseaSupply, NativeSupply,
           SouthSupply, NorthSupply
     FROM ProgrectDetail
)T
UNPIVOT 
(
    SupplyNum FOR Supplier IN
    (OverseaSupply, NativeSupply, SouthSupply, NorthSupply )
) P

执行结果:

以上是关于PG中的行转列示例的主要内容,如果未能解决你的问题,请参考以下文章

hive的行转列和列转行

sql面试:sql中的行转列和列转行

sql的行转列(PIVOT)与列转行(UNPIVOT)

sql的行转列(PIVOT)与列转行(UNPIVOT)

sql的行转列(PIVOT)与列转行(UNPIVOT)

sql的行转列(PIVOT)与列转行(UNPIVOT)