Skip to Main Content
  • Questions
  • How to aggregate records by month year but based on starting date 26th and ending date 25th for each month not based upon calendar months?

Breadcrumb

XMAS_TREE

The AskTOM team is taking a break over the holiday season, so we're not taking questions or responding to comments. Please have a happy and safe festive season and as always, thanks for being a member of the AskTOM community.

Question and Answer

Connor McDonald

Thanks for the question, Khamis .

Asked: July 31, 2024 - 11:35 am UTC

Last updated: August 05, 2024 - 6:55 am UTC

Version: Oracle Database 12c Release 12.2.0.1.0 - 64bit

Viewed 1000+ times

You Asked

How to aggregate records by month year but based on starting date 26th and ending date 25th for each month not based upon calendar months?
For example, I have table:

Order_no Customer_id Date Amount
1001 201 2024-06-11 20:10:00 2000
1002 201 2024-06-25 15:35:00 2100
1003 201 2024-06-26 10:20:00 1700
1004 201 2024-07-15 20:58:00 800
1005 201 2024-07-25 13:45:00 1500
1006 201 2024-07-29 16:25:00 900

I want to produce a year and month aggregation of the sum of the amounts, but periods have a specific start date and end date, for example the start date is 26th and end date 25th of each month.

The result I want:

Customer_id Month Sum_Amount
201 Jun-24 4100
201 Jul-24 4000
201 Aug-24 900

Thanks in advance.

and Connor said...

Something like this perhaps

SQL> with t as
  2   ( select date '2024-05-01' + rownum - 1  created from dual
  3     connect by level <= 100 )
  4  select
  5    created,
  6    trunc(created-23,'MM') as adjusted_mth
  7  from t
  8  order by 1;

CREATED   ADJUSTED_
--------- ---------
01-MAY-24 01-APR-24
02-MAY-24 01-APR-24
03-MAY-24 01-APR-24
04-MAY-24 01-APR-24
05-MAY-24 01-APR-24
06-MAY-24 01-APR-24
07-MAY-24 01-APR-24
08-MAY-24 01-APR-24
09-MAY-24 01-APR-24
10-MAY-24 01-APR-24
11-MAY-24 01-APR-24
12-MAY-24 01-APR-24
13-MAY-24 01-APR-24
14-MAY-24 01-APR-24
15-MAY-24 01-APR-24
16-MAY-24 01-APR-24
17-MAY-24 01-APR-24
18-MAY-24 01-APR-24
19-MAY-24 01-APR-24
20-MAY-24 01-APR-24
21-MAY-24 01-APR-24
22-MAY-24 01-APR-24
23-MAY-24 01-APR-24
24-MAY-24 01-MAY-24
25-MAY-24 01-MAY-24
26-MAY-24 01-MAY-24
27-MAY-24 01-MAY-24
28-MAY-24 01-MAY-24
29-MAY-24 01-MAY-24
30-MAY-24 01-MAY-24
31-MAY-24 01-MAY-24
01-JUN-24 01-MAY-24
02-JUN-24 01-MAY-24
03-JUN-24 01-MAY-24
04-JUN-24 01-MAY-24
05-JUN-24 01-MAY-24
06-JUN-24 01-MAY-24
07-JUN-24 01-MAY-24
08-JUN-24 01-MAY-24
09-JUN-24 01-MAY-24
10-JUN-24 01-MAY-24
11-JUN-24 01-MAY-24
12-JUN-24 01-MAY-24
13-JUN-24 01-MAY-24
14-JUN-24 01-MAY-24
15-JUN-24 01-MAY-24
16-JUN-24 01-MAY-24
17-JUN-24 01-MAY-24
18-JUN-24 01-MAY-24
19-JUN-24 01-MAY-24
20-JUN-24 01-MAY-24
21-JUN-24 01-MAY-24
22-JUN-24 01-MAY-24
23-JUN-24 01-MAY-24
24-JUN-24 01-JUN-24
25-JUN-24 01-JUN-24
26-JUN-24 01-JUN-24
27-JUN-24 01-JUN-24
28-JUN-24 01-JUN-24
29-JUN-24 01-JUN-24
30-JUN-24 01-JUN-24
01-JUL-24 01-JUN-24
02-JUL-24 01-JUN-24
03-JUL-24 01-JUN-24
04-JUL-24 01-JUN-24
05-JUL-24 01-JUN-24
06-JUL-24 01-JUN-24
07-JUL-24 01-JUN-24
08-JUL-24 01-JUN-24
09-JUL-24 01-JUN-24
10-JUL-24 01-JUN-24
11-JUL-24 01-JUN-24
12-JUL-24 01-JUN-24
13-JUL-24 01-JUN-24
14-JUL-24 01-JUN-24
15-JUL-24 01-JUN-24
16-JUL-24 01-JUN-24
17-JUL-24 01-JUN-24
18-JUL-24 01-JUN-24
19-JUL-24 01-JUN-24
20-JUL-24 01-JUN-24
21-JUL-24 01-JUN-24
22-JUL-24 01-JUN-24
23-JUL-24 01-JUN-24
24-JUL-24 01-JUL-24
25-JUL-24 01-JUL-24
26-JUL-24 01-JUL-24
27-JUL-24 01-JUL-24
28-JUL-24 01-JUL-24
29-JUL-24 01-JUL-24
30-JUL-24 01-JUL-24
31-JUL-24 01-JUL-24
01-AUG-24 01-JUL-24
02-AUG-24 01-JUL-24
03-AUG-24 01-JUL-24
04-AUG-24 01-JUL-24
05-AUG-24 01-JUL-24
06-AUG-24 01-JUL-24
07-AUG-24 01-JUL-24
08-AUG-24 01-JUL-24

100 rows selected.

Rating

  (1 rating)

We're not taking comments currently, so please try again later if you want to add a comment.

Comments

Grouping by custom "month"

mathguy, August 05, 2024 - 5:24 pm UTC

From the way you asked the question, I will assume you would know how to group by customer and month, if the month was calendar month - and I will focus only on what is special about the "custom" month definition.

Here is code to generate the test data (which would have been a bit better if it included more than one customer; and, importantly, if it included gaps in the data - "custom" months with no orders from some customers, showing us what you would need in the output in that case):

create table orders (
  order_no    number primary key,
  customer_id number,
  order_date  date,
  amount      number
);

insert into orders (order_no, customer_id, order_date, amount)
  select 1001, 201, timestamp '2024-06-11 20:10:00', 2000 from dual union all
  select 1002, 201, timestamp '2024-06-25 15:35:00', 2100 from dual union all
  select 1003, 201, timestamp '2024-06-26 10:20:00', 1700 from dual union all
  select 1004, 201, timestamp '2024-07-15 20:58:00',  800 from dual union all
  select 1005, 201, timestamp '2024-07-25 13:45:00', 1500 from dual union all
  select 1006, 201, timestamp '2024-07-29 16:25:00',  900 from dual
;

commit;


I (ab?)used the TIMESTAMP literal - less writing than TO_DATE and a full format model; alas the DATE literal does not allow time component. Anyway, this is not important - it's just to create test data.

Note that DATE is an Oracle reserved keyword, so you shouldn't use it as a column name (you could, if you enclosed it in double-quotes - which is generally a poor practice). I used ORDER_DATE instead. Similar comment for the output - I used MTH instead of MONTH to avoid any confusion.

The trick is to use TRUNC(ORDER_DATE - 25, 'month') wherever you would otherwise use just TRUNC(ORDER_DATE, 'month'). The reason for this should be obvious. I believe this is what Connor was suggesting (his answer doesn't seem to address your question in its entirety).

In the SELECT list, I add one month to this (because apparently your "month" is based on the last day in the month, not on the first); and I apply TO_CHAR to control the output, so I can't use MTH from the SELECT list in ORDER BY. Alternatively (and the solution I would prefer) is to use ADD_MONTH(...) in the SELECT list, without applying formatting with TO_CHAR - and then format dates in the output from the user interface (NLS_DATE_FORMAT for example).

select customer_id, 
       to_char(add_months(trunc(order_date - 25, 'month'), 1), 'Mon-rr') as mth,
       sum(amount) as sum_amount
from   orders
group  by customer_id, trunc(order_date - 25, 'month')
order  by customer_id, trunc(order_date - 25, 'month')
;


Output is as requested:

CUSTOMER_ID MTH             SUM_AMOUNT
----------- --------------- ----------
        201 Jun-24                4100
        201 Jul-24                4000
        201 Aug-24                 900