在 SQL 中将列反转为行

Posted

技术标签:

【中文标题】在 SQL 中将列反转为行【英文标题】:Unpivot columns into rows in SQL 【发布时间】:2021-05-08 08:35:10 【问题描述】:

我有一张类似如下的表格:

  date       customer      shop       view       add        buy     
01/01/21      tim          abc         10         5          1             
01/01/21      anna         abc          2         2          2             
02/01/21      anna         hnm          5         4          3             

我想要的输出如下表:

  date       customer      shop       activity       value           
01/01/21      tim          abc         view           10           
01/01/21      tim          abc         add            5        
01/01/21      tim          abc         buy            1     
01/01/21      anna         abc         view           2           
01/01/21      anna         abc         add            2        
01/01/21      anna         abc         buy            2                   
02/01/21      anna         hnm         view           5           
02/01/21      anna         hnm         add            4        
02/01/21      anna         hnm         buy            3   

我想取消透视表,但我不确定最好的方法是什么? UNNEST() 是正确的方法吗?这是我尝试过的查询,但它不起作用:

SELECT date,
       customer, 
       shop,
       UNNEST(ARRAY['view', 'add', 'buy']) AS activity
       UNNEST(ARRAY[view, add, buy]) AS value
FROM table 
GROUP BY date, customer, shop 

如果您能给我任何建议,我们将不胜感激。

【问题讨论】:

【参考方案1】:

在 Redshift 中,union all 可能是最简单的方法:

select date, customer, shop, 'view' as activity, view as value 
from t
union all
select date, customer, shop, 'add' as activity, add as value 
from t
union all
select date, customer, shop, 'buy' as activity, buy as value 
from t;

您还可以使用casecross join 进行反透视:

select t.date, t.customer, t.shop, x.activity,
       (case x.activity when 'view' then t.view when 'add' then t.add when 'buy' then t.buy end) as value
from t cross join
     (select 'view' as activity union all
      select 'add' as activity union all
      select 'buy' as activity
     ) x;

请注意,聚合不是必需的。

【讨论】:

感谢您的精彩提示,我不知道在这种情况下也可以使用 UNION ALL @tlqn 。 . .我确实认为这是更好的答案,因为不需要聚合来做你想做的事。 感谢@GordonLinoff 的精彩回答,只是想知道如何使用枢轴 @pc_pyr 。 . . Redshift 不支持pivot【参考方案2】:

我认为您在这里不需要任何非标准 SQL,只需要交叉连接和一些条件聚合:

select
       date, customer, shop, activity
     , max(case when activity = 'view' then view
                when activity = 'add'  then add
                when activity = 'buy'  then buy end) as value
from mytable
cross join (
    select 'view' as activity union all
    select 'add' union all
    select 'buy'
    ) d
group by
      date, customer, shop, activity
order by
      date, customer, shop, activity

产生以下结果:

     date    | customer | shop | activity | value 
 ------------|----------|------|----------|------- 
  2021-01-01 | anna     | abc  | add      |     2 
  2021-01-01 | anna     | abc  | buy      |     2 
  2021-01-01 | anna     | abc  | view     |     2 
  2021-01-01 | tim      | abc  | add      |     5 
  2021-01-01 | tim      | abc  | buy      |     1 
  2021-01-01 | tim      | abc  | view     |    10 
  2021-01-02 | anna     | hnm  | add      |     4 
  2021-01-02 | anna     | hnm  | buy      |     3 
  2021-01-02 | anna     | hnm  | view     |     5 

基于 Postgres 的演示 here

【讨论】:

以上是关于在 SQL 中将列反转为行的主要内容,如果未能解决你的问题,请参考以下文章

在SQL中将列转换为行

在 ORACLE SQL 中将一组列转换为行

如何在 Sql Server 2008 R2 中将列转换为行?

将列反转为行(oracle)

在Oracle中将列转换为行[重复]

在python中将列转换为行[重复]