Hi:
The key is NOT to do the addition on the FIRST.MONTH condition -- all you probably want to do at FIRST.MONTH is reset the cumulative variable to 0.
Consider this data sorted by month product and day. I have added what the values for first.month and last.month will look like on every observation. So you can see that when first.month = 1 SAS is reading the first observation for the month -- at this point you want to set your month accumulator variable to 0. But when SAS is reading ROW 2, 3, 4, etc, you want to keep adding those values for AMT to your accumulator variable. In your logic, you were only adding the number for the first row of your group, which will not get you a running total for every month:
[pre]
product month day amt first.month last.month
shirts 01 1 120 1 0
shirts 01 2 130 0 0
shirts 01 3 155 0 0
shirts 01 4 150 0 0
shoes 01 1 100 0 0
shoes 01 2 150 0 0
shoes 01 3 175 0 0
shoes 01 4 100 0 1
**************************change between months**********
shirts 02 1 89 1 0
shirts 02 2 120 0 0
shirts 02 3 60 0 0
shirts 02 4 150 0 0
shoes 02 1 99 0 0
shoes 02 2 100 0 0
shoes 02 3 60 0 0
shoes 02 4 100 0 1
[/pre]
Assume that we want to accumulate a monthly running total, a "grand" running total and for every month, we also want a running total for shirts and shoes. I need several "accumulator variables" -- MONTOT, GRNDTOT, SHIRTTOT and SHOETOT.
What I want on every observation is to add the AMT on that row to both MONTOT and GRNDTOT -- however, I want to conditionally add AMT to either SHIRTTOT or SHOETOT, depending on the value of PRODUCT.
So this program will do that:
[pre]
data mon_data;
infile datalines;
input product $ month $ day amt;
return;
datalines;
shoes 01 1 100
shoes 01 2 150
shoes 01 3 175
shoes 01 4 100
shoes 02 1 99
shoes 02 2 100
shoes 02 3 60
shoes 02 4 100
shirts 01 1 120
shirts 01 2 130
shirts 01 3 155
shirts 01 4 150
shirts 02 1 89
shirts 02 2 120
shirts 02 3 60
shirts 02 4 150
;
run;
proc sort data=mon_data;
by month product day;
run;
data work.calculated1
sumonly(keep=month montot shirttot shoetot);
set work.mon_data;
by Month;
** I like to use an explicit RETAIN statement;
retain montot shirttot shoetot grndtot 0 ;
** Use first.month condition to set cum variables to 0;
if first.month then do;
montot = 0;
shirttot = 0;
shoetot = 0;
end;
** add the amount for every observation;
montot + amt;
grndtot + amt;
** add the amount for shirt and shoes separately;
if product = 'shirts' then shirttot + amt;
else if product = 'shoes' then shoetot + amt;
** output calculated1 -- same number of obs out as obs in;
output calculated1;
** output monthly totals for last.month condition;
if last.month then output sumonly;
run;
proc print data=work.calculated1;
title 'see different running totals';
run;
proc print data=work.sumonly;
title 'summary file';
run;
[/pre]
If you were going to accumulate on DAY, then you'd use slightly different logic, but the basic idea is
the same -- you use FIRST.byvar to initialize or reset your accumulator variable to 0. Then you just add your numbers on every row.
As you can see with SHIRTTOT and SHOETOT -- at some point, the accumulator variable value just repeats on every row because there are no new values to add to the number. They're not worth much as running totals, but if you want to make a summary data set of ONLY monthly totals without products or days -- like SUMONLY -- then they do serve a purpose. By the time the LAST.MONTH observation is being held in the input buffer you have all the information you need to output MONTH, MONTOT, SHIRTTOT and SHOETOT. The program output is shown below.
cynthia
[pre]
see different running totals
Obs product month day amt montot shirttot shoetot grndtot
1 shirts 01 1 120 120 120 0 120
2 shirts 01 2 130 250 250 0 250
3 shirts 01 3 155 405 405 0 405
4 shirts 01 4 150 555 555 0 555
5 shoes 01 1 100 655 555 100 655
6 shoes 01 2 150 805 555 250 805
7 shoes 01 3 175 980 555 425 980
8 shoes 01 4 100 1080 555 525 1080
9 shirts 02 1 89 89 89 0 1169
10 shirts 02 2 120 209 209 0 1289
11 shirts 02 3 60 269 269 0 1349
12 shirts 02 4 150 419 419 0 1499
13 shoes 02 1 99 518 419 99 1598
14 shoes 02 2 100 618 419 199 1698
15 shoes 02 3 60 678 419 259 1758
16 shoes 02 4 100 778 419 359 1858
***************************************************************************************
summary file
Obs month montot shirttot shoetot
1 01 1080 555 525
2 02 778 419 359
[/pre]