Запрос Postgresql для переноса столбцов в строки

#sql #postgresql #unpivot

#sql #postgresql #открепить

Вопрос:

У меня есть таблица, подобная этой:

 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
 

Ответ №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<> демонстрация скрипки

Вывод:

  ----------- ---------- 
| 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 |
 ----------- ---------- 
 

Комментарии:

1. спасибо Лукашу, но я хочу, чтобы отображались только те, у которых соответствующее значение больше нуля … и появляться столько раз, сколько стоит значение

2. @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 classe_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)