具有多列和工作日的 PostgreSQL 交叉表查询

问题描述 投票:0回答:2

我尝试通过对几列进行分组来创建数据透视表:用户 ID、姓名、周数和日期名称。 当前的请求没有给出期望的结果。 我需要帮助。

这是我的桌子:

user_id name    week_number day_name    price
2       Luc     8           Sunday      10
2       Luc     8           Monday      15
2       Luc     8           Tuesday     8
2       Luc     8           Wednesday   2
2       Luc     8           Thursday    9
2       Luc     8           Friday      9
2       Luc     8           Saturday    11
2       Luc     9           Saturday    1
2       Luc     9           Friday      13
3       Mathieu 8           Sunday      22
3       Mathieu 8           Monday      13
3       Mathieu 8           Tuesday     9
3       Mathieu 8           Wednesday   3

这是我当前的要求:

SELECT *
FROM   crosstab(
'SELECT user_id, name, week_number,day_name,price
FROM   table_1
ORDER  BY 1,2,3,4' 
) AS ct (
"user_id" integer,
"day_name" text,
"Sunday" integer,   
"Monday" integer,   
"Tuesday" integer,  
"Wednesday" integer,    
"Thursday" integer, 
"Friday" integer,   
"Saturday" integer
);

这是我想要得到的结果。

postgresql pivot grouping pivot-table crosstab
2个回答
6
投票

您可以只使用条件聚合:

SELECT user_id, name, week_number
       MAX(price) FILTER (WHERE day_name = 'Sunday') as Sunday,
       MAX(price) FILTER (WHERE day_name = 'Monday') as Monday,
       MAX(price) FILTER (WHERE day_name = 'Tuesday') as Tuesday,
       MAX(price) FILTER (WHERE day_name = 'Wednesday') as Wednesday,
       MAX(price) FILTER (WHERE day_name = 'Thursday') as Thursday,
       MAX(price) FILTER (WHERE day_name = 'Friday') as Friday,
       MAX(price) FILTER (WHERE day_name = 'Saturday') as Saturday
FROM table_1
GROUP BY user_id, name, week_number
ORDER BY user_id, name, week_number;

编辑:

你可以在没有

FILTER
的情况下编写相同的逻辑:

       MAX(CASE WHEN day_name = 'Sunday' THEN price END) as Sunday,

2
投票

下面的 SQL 使用

crosstab
函数,仅使用额外的列
uniuq_id
即可给出预期结果。

SELECT *
FROM   crosstab(
        'SELECT CONCAT(user_id,name,week_number) as unique_id,
             user_id,name,week_number,day_name,price
             FROM table_1
             ORDER BY unique_id',
        'SELECT day_name FROM (VALUES (''Monday''), (''Tuesday''),
            (''Wednesday''), (''Thursday''), (''Friday''),
            (''Saturday''), (''Sunday'')) b(day_name)'
       ) AS ct (
             "unique_id" varchar,
             "user_id" integer,
             "name" varchar,
             "week_number" integer,
             "Monday" integer,  
             "Tuesday" integer,  
             "Wednesday" integer,    
             "Thursday" integer,
             "Friday" integer,  
             "Saturday" integer,
             "Sunday" integer
           );

解释

根据Postgresql官方文档

crosstab
函数有3组参数

  1. 交叉表(sql文本)→记录集
  2. 交叉表(源_sql文本,类别_sql文本)→记录集
  3. 交叉表(sql文本,N个整数)→记录集

在问题中,您实际上使用的是第一个

crosstab
,并且它期望
sql text
仅返回具有特定含义的 3 列:

row_name    cat    value
----------+-------+-------
row1      cat1    val1
row1      cat2    val2
row2      cat1    val3

并且

crosstab
将上面的表格旋转为下面的格式:

row_name    cat1    cat2
----------+-------+-------
row1        val1    val2
row2        val3    null

问题中的 SQL 返回 5 列,这会导致语法错误。

在这种情况下,我们需要使用

crosstab
的第二种形式:

crosstab(source_sql, category_sql)

source_sql
仅遵循以下规则即可返回 3 列以上:

  • 第一列是 row_id
  • 最后 2 列是类别列和值列
  • 额外的列是中间的列

为了组成这样的

source_sql
,请使用以下语句:

SELECT CONCAT(user_id,name,week_number) as unique_id,
      user_id,name,week_number,day_name,price
FROM table_1
ORDER BY unique_id

category_sql
返回我们期望转换为列的值,下面的语句仅按预期顺序返回工作日。

SELECT day_name FROM (VALUES ('Monday'), ('Tuesday'), ('Wednesday'), ('Thursday'), ('Friday'), ('Saturday'), ('Sunday')) b(day_name)

总而言之,我们首先得到了完整的 SQL。

© www.soinside.com 2019 - 2024. All rights reserved.