Как развернуть строки в столбцы по месяцам?
Есть таблица с полями (id, name, count, date).
Как можно составить запрос, чтобы он выдавал name и 12 месяцев со значением count в каждом?
То есть, результат запроса должен выглядеть примерно так:
name | jan | feb | mar | apr | may | jun | jul | aug | sep | oct | nov | dec
sasha| 1 | 5 | 0 | 0 | 0 | 0 | 5 | 7 | 0 | 1 | 3 | 0
petya| 3 | 7 | 2 | 7 | 1 | 0 | 1 | 2 | 1 | 0 | 0 | 1
Делал подзапросы, то есть для каждого месяца и каждого имени отдельно просчитывал count, получается сильно долгий запрос, несколько минут делается.
Думал про listagg, но нужна именно такая таблица в результате.
Ответы (4 шт):
Автор решения: Alex R.
→ Ссылка
select
*
from
(select name, count, extract(month from date) mnum from my_table)
pivot
(sum(count) for mnum in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12))
Автор решения: 0xdb
→ Ссылка
Можно с функцией PIVOT, с которой ознакомиться можно тут. Воспроизводимый пример:
with data (name, qty, dt) as (
select
case mod (rownum, 2) when 0 then 'Саша' else 'Петя' end,
mod (rownum, 2)+1, date'2020-01-01'+(rownum-1)
from dual connect by level<=365
)
--## Отсюда начинается сам запрос
select * from (
select name, qty, to_char (dt, 'mon') mon from data)
pivot (sum (qty) for mon in (
'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'));
Результат (каждый второй день, Петя даёт две единицы, а Саша одну):
NAME 'jan' 'feb' 'mar' 'apr' 'may' 'jun' 'jul' 'aug' 'sep' 'oct' 'nov' 'dec'
-------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
Петя 32 28 32 30 30 30 32 30 30 32 30 30
Саша 15 15 15 15 16 15 15 16 15 15 15 15
Автор решения: Yaroslav
→ Ссылка
Примерчие без case и с полными названияями месяцев.
select * from
(
select
tDV.testTableName as name,
tDV.testTableCount as length,
trim(to_char(to_date(tDV.testTableDate, 'DD-MM-YYYY'), 'Month')) as month
from testTable tDV
) t
pivot (sum(lenght) for month in (
'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'));
Автор решения: 4per
→ Ссылка
Всё-таки я предложу case, дабы не pivot единым.
select
d.name,
sum(case extract(month from d.date) when 1 then 1 else 0 end) jan,
sum(case extract(month from d.date) when 2 then 1 else 0 end) feb,
sum(case extract(month from d.date) when 3 then 1 else 0 end) mar,
sum(case extract(month from d.date) when 4 then 1 else 0 end) apr,
sum(case extract(month from d.date) when 5 then 1 else 0 end) may,
sum(case extract(month from d.date) when 6 then 1 else 0 end) jun,
sum(case extract(month from d.date) when 7 then 1 else 0 end) jul,
sum(case extract(month from d.date) when 8 then 1 else 0 end) aug,
sum(case extract(month from d.date) when 9 then 1 else 0 end) sep,
sum(case extract(month from d.date) when 10 then 1 else 0 end) oct,
sum(case extract(month from d.date) when 11 then 1 else 0 end) nov,
sum(case extract(month from d.date) when 12 then 1 else 0 end) dec
from data d
group by d.name
