【问题标题】:Postgresql query to transpose columns to rowsPostgresql 查询将列转置为行
【发布时间】:2020-12-01 19:57:45
【问题描述】:

我有一张这样的桌子:

id_edifc classe_a classe_b classe_c
9001 0 0 1
9002 1 1 1
9003 0 1 2
9004 0 0 0
9005 1 1 0

我想把它想象成这样:

id_edifc classe
9001 classe_c
9002 classe_a
9002 classe_b
9002 classe_c
9003 classe_b
9003 classe_c
9003 classe_c
9004 NULL
9005 classe_a
9005 classe_b

【问题讨论】:

    标签: sql postgresql unpivot


    【解决方案1】:

    使用横向:

    SELECT t.id_edifc, s.name
    FROM tab t
    ,LATERAL ( VALUES (classe_a, 'classe_a')
                     ,(classe_b, 'classe_b')
                     ,(classe_c, 'classe_c'))s(val, name)
    WHERE val = 1;
    

    处理行中的所有零并复制值:

    SELECT t.id_edifc, s2.name
    FROM tab t
    LEFT JOIN LATERAL (SELECT s.name
                      FROM (VALUES  (classe_a, 'classe_a')
                                   ,(classe_b, 'classe_b')
                                   ,(classe_c, 'classe_c'))s(val, name)
                       ,LATERAL generate_series(1,s.val)
                       WHERE val > 0
                     ) s2 ON TRUE
    ORDER BY t.id_edifc;
    

    db<>fiddle demo

    输出:

    +-----------+----------+
    | id_edifc  |   name   |
    +-----------+----------+
    |     9001  | classe_c |
    |     9002  | classe_a |
    |     9002  | classe_b |
    |     9002  | classe_c |
    |     9003  | classe_b |
    |     9003  | classe_c |
    |     9003  | classe_c |
    |     9004  | NULL     |
    |     9005  | classe_a |
    |     9005  | classe_b |
    +-----------+----------+
    

    【讨论】:

    • 感谢lukasz,但我只希望那些对应值大于零的值出现......并且出现的次数与值的值一样
    • @ishankaganepola I want only those with corresponding value greater than zero to appear... and to appear as many times as the value is worth - 9003 case_c 是两次,它被复制了多次
    【解决方案2】:

    使用jsonb 函数允许您对任意数量的列执行此操作:

    with pvt as (
      select id_edifc, k as classe
        from xpose
             cross join lateral to_jsonb(xpose)  as j(obj)
             cross join lateral jsonb_each_text(obj - 'id_edifc') as e(k, v)
             cross join lateral generate_series(1, v::int)
    )
    select x.id_edifc, p.classe
      from xpose x
           left join pvt p
             on p.id_edifc = x.id_edifc
     order by x.id_edifc, p.classe;
    
    ┌──────────┬──────────┐
    │ id_edifc │  classe  │
    ├──────────┼──────────┤
    │     9001 │ classe_c │
    │     9002 │ classe_a │
    │     9002 │ classe_b │
    │     9002 │ classe_c │
    │     9003 │ classe_b │
    │     9003 │ classe_c │
    │     9003 │ classe_c │
    │     9004 │          │
    │     9005 │ classe_a │
    │     9005 │ classe_b │
    └──────────┴──────────┘
    (10 rows)
    
    

    【讨论】:

      猜你喜欢
      • 2017-09-18
      • 2012-03-29
      • 2012-12-14
      • 1970-01-01
      • 2018-12-08
      • 1970-01-01
      • 1970-01-01
      • 2019-06-22
      • 2020-03-06
      相关资源
      最近更新 更多