【问题标题】:Postgres Crosstab query Dynamic pivotPostgres 交叉表查询 动态数据透视
【发布时间】:2020-04-22 07:11:29
【问题描述】:

有人知道如何在 Postgres 中创建以下交叉表吗?

例如我有下表:

Store      Month        Sales
A          Mar-2020     100
A          Feb-2020     200
B          Mar-2020     400
B          Feb-2020     500
A          Jan-2020     400
C          Apr-2020     600

我希望查询返回以下交叉表,列标题不应是硬编码值,而是反映第一个表中“月”列中的值:

Store    Jan-2020    Feb-2020    Mar-2020    Apr-2020
A        400         200         100         -
B        -           500         400         -
C        -           -           -           600

这可能吗?

【问题讨论】:

  • 想强调我的目标是动态地从第一个表中提取列标题而不是硬编码它们,因为数据每个月都会发生变化。这可能吗?
  • 不,不可能。查询的列数、类型和名称必须为数据库查询开始之前知道
  • 谢谢。有点切题,但您知道是否可以将列别名为日期?例如选择 sum(this_month.sales) 作为 DATE_TRUNC('month', current_date)?我的示例在这里不起作用,但想看看是否有其他方法可以做到这一点。

标签: sql postgresql crosstab


【解决方案1】:

Postgres 确实有一个crosstab 函数,但我认为在这种情况下使用内置过滤功能很简单:

select store,
       sum(sales) filter (where month = 'Jan-2020') as Jan_2020,
       sum(sales) filter (where month = 'Feb-2020') as Feb_2020,
       sum(sales) filter (where month = 'Mar-2020') as Mar_2020,
       sum(sales) filter (where month = 'Apr-2020') as Apr_2020
from t
group by store
order by store;

注意:这会将NULL 值放在没有对应值的列中,而不是-。如果您真的想要连字符,则需要将值转换为字符串——这似乎是不必要的复杂。

【讨论】:

  • 谢谢,是否可以从数据中提取列标题而不是硬编码?我的表只是一个示例,但将包含最近 N 个月的销售额,因此该数据每个月都会更改。例如下个月将包含 May-2020,并且每月编辑一次查询是不可行的。
  • @user2491463 。 . .这需要动态数据透视和某种动态 SQL。
【解决方案2】:

尝试在SUM() 中使用CASE 表达式,这里是db-fiddle

select
    store,
    sum(case when month = 'Jan-2020' then sales end) as "Jan-2020",
    sum(case when month = 'Feb-2020' then sales end) as "Feb-2020",
    sum(case when month = 'Mar-2020' then sales end) as "Mar-2020",
    sum(case when month = 'Apr-2020' then sales end) as "Apr-2020"
from myTable
group by
   store
order by
   store

输出:

+---------------------------------------------------+
|store  Jan-2020    Feb-2020    Mar-2020    Apr-2020|
+---------------------------------------------------+
| A        400         200         100         null |
| B        null        500         400         null |
| C        null        null        null        600  |
+---------------------------------------------------+

如果您想在输出中将null 值替换为0,请使用coalesce()

例如

coalesce(sum(case when month = 'Jan-2020' then sales end), 0)

【讨论】:

  • 谢谢,是否可以从数据中提取列标题而不是硬编码?我的表只是一个示例,但将包含最近 N 个月的销售额,因此该数据每个月都会更改。例如下个月将包含 May-2020,并且每月编辑一次查询是不可行的。
猜你喜欢
  • 2012-04-07
  • 1970-01-01
  • 1970-01-01
  • 2011-03-29
  • 2012-06-06
  • 2011-04-03
  • 2016-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多