在多列中按日期范围对值求和

Sum values by date range in multiple columns

我需要按日期范围对多个列中的值求和。每个日期范围都是一个月中的一周。如果是月初或月末,则可以短于 7 天。 例如,我有 2 月的日期:

my_user        my_date        my_value
A              01.02.2019     100
A              02.02.2019     150
B              01.02.2019     90
Z              28.02.2019     120

如何使用如下所示的日期范围格式?

my_user   01/02-03/02   04/02-10/02   11/02-17/02  18/02-24/02  25/02-28/02
A              250      0             0            0            0 
B              90       0             0            0            0 
Z              0        0             0            0            120 

有什么建议吗?谢谢!

你可以这样做:

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

demo

USR          1          2          3          4          5          6
--- ---------- ---------- ---------- ---------- ---------- ----------
A          250                                             
B                                            90            
Z                                                      120

Header 数字是一个月中的第几周。如果月份从本周末开始并且超过 28 天,则最大值可能为 6。

如果需要,您可以使用类似的方法找到每周的第一天和最后一天,但您不能将它们作为 headers,或者至少不容易。


编辑:

it is possible to define certain date range with pivot, simple as two dates? For example, I need to sum values from 5 December 2018 to 4 January 2019, 5 January 2019 to 4 February 2019, 5 March 2019 to 4 April 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)

没有简单的方法可以避免手动列出它们。如果您需要它,请在 SO 中寻找 oracle dynamic pivot,那里已经有数百个类似的问题。 ;-)