BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
saf_nadia
Fluorite | Level 6
I have data like this:
Id date cb
X 1jan 27
Y 1jan 47
X 2jan 10
Y 2jan 13
X 3jan 37

Each Id have a cap of 50 for total cb (let cb2)
I want an output to be like this:

Id date Cb Cb2
X 1jan 27 27
Y 1jan 47 47
X 2jan 10 10
Y 2jan 13 3
X 3jan 37 13

Hope you guys can help
1 ACCEPTED SOLUTION

Accepted Solutions
PGStats
Opal | Level 21

You mean, something like this?

 

data have;
input Id $ date :date9. cb;
format date date5.;
datalines;
X 1jan2019 27
Y 1jan2019 47
X 2jan2019 10
Y 2jan2019 13
X 3jan2019 37
;

proc sort data=have; by id date; run;

%let limit=50;

data want;
s = 0;
do until(last.id);
    set have; by id;
    cb2 = max(0, min(cb, &limit. - s)); 
    s = s + cb;
    output;
    end;
drop s;
run;

proc sort data=want; by date id; run;

proc print data=want noobs; run;
PG

View solution in original post

5 REPLIES 5
mkeintz
PROC Star

I think I understand that new variable CB2 should never exceed 50, but I don't understand any other rule you have in mind for CB2.

 

What are your rules of constructing CB2?

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------
saf_nadia
Fluorite | Level 6
I need cb2 to calculate the total of the whole dataset so that the total does not exceed the limit (let say the total of all cb2 should less than 100).
mkeintz
PROC Star

OK, I get it now.  For each ID, you want to maintain a cumulative sum of CB.  As long as the sum is <= 50, CB2=CB. But if it exceeds 50, then CB2 is the value that brings the sum to exactly 50.

 

If your data were sorted by ID/DATE, you could just keep a cumulative sum (CBSUM) to guide your assignment of CB2.Then resort to original order (by DATE/ID):

 

data have;
input Id $ date date9. cb;
format date date9.;
datalines;
X 1jan2018 27
Y 1jan2018 47
X 2jan2018 10
Y 2jan2018 13
X 3jan2018 37
Y 3jan2018 11
run;


proc sort data=have; 
  by id date;
run;
data want (drop=cbsum);
  set have;
  by id;
  if first.id then cbsum=0;
  if cbsum>50 then cb2=0;
  else cb2=min(50-cbsum,cb);
  cbsum+cb;
run;
proc sort;
  by date id;
run;

Note that CBSUM is retained across observations, due to the "summing statement" ( CBSUM+CB).

 

 

If you want to avoid sorting then you could keep a CBSUM value for each ID, in a hash object:

 

data want (drop=cbsum);
  set have;
  if _n_=1 then do;
    declare hash h ();
      h.definekey('id');
      h.definedata('cbsum');
      h.definedone();
  end;
  if h.find()^=0 then cbsum=0;
  if cbsum>50 then cb2=0;
  else cb2=min(50-cbsum,cb);
  cbsum+cb;
  h.replace();
run;
--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------
PGStats
Opal | Level 21

You mean, something like this?

 

data have;
input Id $ date :date9. cb;
format date date5.;
datalines;
X 1jan2019 27
Y 1jan2019 47
X 2jan2019 10
Y 2jan2019 13
X 3jan2019 37
;

proc sort data=have; by id date; run;

%let limit=50;

data want;
s = 0;
do until(last.id);
    set have; by id;
    cb2 = max(0, min(cb, &limit. - s)); 
    s = s + cb;
    output;
    end;
drop s;
run;

proc sort data=want; by date id; run;

proc print data=want noobs; run;
PG
saf_nadia
Fluorite | Level 6
Thanks a lot for your reply! The code works really well!

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 5 replies
  • 1012 views
  • 3 likes
  • 3 in conversation