使用 PostgreSQL 创建数据透视表

Posted

技术标签:

【中文标题】使用 PostgreSQL 创建数据透视表【英文标题】:Create a pivot table with PostgreSQL 【发布时间】:2014-01-04 06:44:15 【问题描述】:

假设我在 Postgres 中有一个名为 listings 的表,如下所示:

id    neighborhood    bedrooms    price
1     downtown        0           256888
2     downtown        1           334000
3     riverview       1           505000
etc.

如何编写交叉表查询,将每间卧室的平均价格显示为列,将街区显示为行?

查询的输出应该是这样的(数字是组成的,列是卧室):

            0       1       2       3
riverton    250000  300000  350000  -
downtown    189000  325000  -       450000

【问题讨论】:

【参考方案1】:

首先用聚合函数avg()计算平均值:

SELECT neighborhood, bedrooms, avg(price)
FROM   listings
GROUP  BY 1,2
ORDER  BY 1,2

然后按照此相关答案中的详细说明将结果提供给crosstab() 函数:

PostgreSQL Crosstab Query

【讨论】:

@Avishai:(全功能)带有位置引用的语法简写,GROUP BY neighborhood, bedrooms的缩写【参考方案2】:

在 Postgres 中构建数据透视表的最佳方式是 CASE 表达式。

SELECT neighborhood,
       round(avg((CASE WHEN bedrooms = 0 THEN price END)), 2) AS "0",
       round(avg((CASE WHEN bedrooms = 1 THEN price END)), 2) AS "1",
       round(avg((CASE WHEN bedrooms = 2 THEN price END)), 2) AS "2",
       round(avg((CASE WHEN bedrooms = 3 THEN price END)), 2) AS "3"
FROM listings
GROUP BY neighborhood;

对问题数据运行此操作会产生

NEIGHBORHOOD                  0          1          2          3
-------------------- ---------- ---------- ---------- ----------
downtown                 256888     334000       NULL       NULL
riverview                  NULL     505000       NULL       NULL

【讨论】:

这个使用 case 语句的特定示例是不正确的。声明round(avg((case when bedroom = 0 then price else 0 end)),2) 表示每间卧室超过 0 间的公寓在取平均值时被视为价格为 0 的 0 间卧室。 看,我在这里使用您的方法为我的转置/透视查询做了类似的方法。如果我 DONT 添加avg 函数(在这种情况下,让我们说bedroom)Postgres 会抱怨并说bedroom 也需要与neighborhood 组合在一起.你知道为什么avg 删除了附加组吗? @Evan Allen,我同意这通常很简单,因为您有一定数量的列可以作为枢轴。我认为您的查询可以简单得多,但是考虑将其更改为CASE WHEN bedrom = 0 THEN price END,与CASE .... ELSE NULL END 相同,这样聚合函数就会忽略这些。我建议编辑,但队列已满【参考方案3】:

使用过滤器实现的另一种解决方案:

SELECT neighborhood,
   avg(price) FILTER (WHERE bedrooms = 0) AS "0",
   avg(price) FILTER (WHERE bedrooms = 1) AS "1",
   avg(price) FILTER (WHERE bedrooms = 2) AS "2",
   avg(price) FILTER (WHERE bedrooms = 3) AS "3"
FROM listings
GROUP BY neighborhood;

【讨论】:

以上是关于使用 PostgreSQL 创建数据透视表的主要内容,如果未能解决你的问题,请参考以下文章

怎样设置PostgreSQL中字段和表名对大小写敏感

使用 Redshift (PostgreSQL) 和计数的数据透视表

Postgresql 如何在 SQL 数据库上透视表

在 laravel 中使用多对多关系同步:PostgreSQL 数据透视表不更新

使用 PostgreSQL 的数据透视视图

PostgreSQL 交叉表/数据透视问题