I have a PostgreSQL table which gives me the following output:
country | metric_code | male | female | pensioners | teenagers |
---|---|---|---|---|---|
us | metric_1 | 10 | 14 | 22 | 30 |
us | metric_2 | 105 | 142 | 222 | 309 |
uk | metric_1 | 15 | 13 | 9 | 21 |
uk | metric_2 | 212 | 264 | 440 | 165 |
create table tbl (
region text,
metric_code text,
"male" int,
"female" int,
"pensioners" int,
"teenagers" int
);
insert into tbl(region, metric_code, "male", "female", "pensioners", "teenagers")
values
('us', 'metric_1', 10, 14, 22, 30),
('us', 'metric_2', 105,142,222,309),
('uk', 'metric_1', 15,13,9,21),
('uk', 'metric_2', 212,264,440,165);
Now I want the Output as below:
country | predicate_code | metric_1 | metric_2 |
---|---|---|---|
us | male | 10 | 105 |
us | female | 14 | 142 |
us | pensioners | 22 | 222 |
us | teenagers | 30 | 309 |
uk | male | 15 | 212 |
uk | female | 13 | 264 |
uk | pensioners | 9 | 440 |
uk | teenagers | 21 | 165 |
How to do this?
I wrote this query:
select region, predicate_code,
max(case when metric_code = 'metric_1' then value end) as metric_1,
max(case when metric_code = 'metric_2' then value end) as metric_2
from tbl t
cross join lateral (
values
('male', "male"),
('female', "female"),
('pensioners', "pensioners"),
('teenagers', "teenagers")
) as v(predicate_code, value)
group by region, predicate_code
order by 1, 2
are there any other ways? without group by / case?
3
Answers
fiddle
Update : Using dynamic transpose :
I would flip the table into
jsonb
and then usejsonb_each_text()
to get the rows desired, usinggroup by
to combinemetric_1
andmetric_2
into single rows:Working fiddle
Try this out: