Вы можете сделать это:
select *
from (
select to_char(dt, 'iw') - to_char(trunc(dt, 'month'), 'iw') + 1 wk, usr, val from t)
pivot (sum(val) for wk in (1, 2, 3, 4, 5, 6))
демо
USR 1 2 3 4 5 6
--- ---------- ---------- ---------- ---------- ---------- ----------
A 250
B 90
Z 120
Номера заголовков - неделимесяца.Максимум может быть 6, если месяц начинается в конце недели и дольше 28 дней.
Аналогично вы можете найти первый и последний день каждой недели, если это необходимо, но вы не можете поместить их в качестве заголовков.или, по крайней мере, нелегко.
Редактировать:
можно определить определенный диапазон дат с помощью сводной, просто как две даты?Например, мне нужно сложить значения с 5 декабря 2018 года по 4 января 2019 года, с 5 января 2019 года по 4 февраля 2019 года, с 5 марта 2019 года по 4 апреля 2019 года
Да.Все зависит от того, как мы рассчитываем первую и последующие недели.Здесь:
to_char(dt, 'iw') - to_char(trunc(dt, 'month'), 'iw') + 1
Я вычитаю неделю в году для данной даты и неделю в году первого дня в месяце для этой даты.Вы можете просто заменить это второе значение начальной датой, либо жестко закодировав его в своем запросе, либо отправив параметр в запрос или найдя минимальную дату сначала в подзапросе:
(to_char(dt, 'iw') - to_char(date '2019-03-05', 'iw')) + 1
или
(to_char(dt, 'iw') - to_char((select min(dt) from data), 'iw')) + 1
Редактировать 2:
Однако есть одна проблема.Когда определенный пользователем период содержит два или более лет.to_date(..., 'iw')
отлично работает в течение одного года, но для двух мы получаем значения 51, 52, 01, 02 ... Мы должны как-то с этим справиться, например, вот так:
with t(dt1, dt2) as (select date '2018-12-16', date '2019-01-15' from dual)
select min(dt) mnd, max(dt) mxd, iw, row_number() over (order by min(dt)) rn
from (select dt1 + level - 1 dt, to_char(dt1 + level - 1, 'iw') iw
from t connect by level -1 <= dt2 - dt1)
group by iw
, что дает нам:
MND MXD IW RN
----------- ----------- -- ----------
2018-12-16 2018-12-16 50 1
2018-12-17 2018-12-23 51 2
2018-12-24 2018-12-30 52 3
2018-12-31 2019-01-06 01 4
2019-01-07 2019-01-13 02 5
2019-01-14 2019-01-15 03 6
В первой строке у нас есть определенные пользователем диапазоны дат.Затем я выполнил иерархический запрос по всем датам в диапазоне, присваивающем week
, затем сгруппировал по этой неделе, нашел даты начала и окончания для каждой недели и присвоил номер строки rn
, который может в дальнейшем использоваться сводной таблицей.* Теперь вы можете просто объединить свои входные данные с этим запросом, назовем его weeks
:
from data join weeks on dt between mnd and mxd
и сделать pivot.Но для более длительных периодов вы должны найти, сколько может быть недель, и указать их в сводной статье in (1, 2, 3, 4...)
.Вы также можете добавить псевдонимы, если вам нужно:
pivot ... for rn in (1 week01, 2 week02... 12 week12)
Нет простого способа избежать их перечисления вручную.Если вам это нужно, поищите oracle dynamic pivot
в SO, там уже сотни похожих вопросов.; -)