BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
theponcer
Quartz | Level 8

I have a data table that needs to be adjusted. I have a separate table that includes the type of adjustment. Both tables contain ID and month fields. I believe I should be able to use a hash iterator to find the ID/month combo that needs to be adjusted, adjust any necessary fields, and then move to the next month within that ID that needs to be adjusted (if necessary). However, I am not sure how to code this because I am not familiar with using hash iterators. I realize I could do this code if all of the ID/Month/Adjustment combinations were in the hash table, but I am trying to use the hash iterator. I am thinking it would look something like this:

 

 

 

Rules         
1) If you Quit Your Job, you stop receiving your $1 paycheck in that month and all subsequent months
2) If you get a raise, you get a $1 boost to your paycheck for that month and all subsequent months
3) If you win the lottery, you get $1,000,000 in addition to your paycheck for that month only 

 

Have - Data Table  
IDNameMonthMoney
1BillyJan$1
1BillyFeb$1
1BillyMar$1
2WillyJan$1
2WillyFeb$1
2WillyMar$1
3JillyJan$1
3JillyFeb$1
3JillyMar$1

 

Have - Hash Table 
IDMonthAdjustment
1FebQuit Job
2JanGot a Raise
3MarWon the Lottery

 

Want   
IDNameMonthMoney
1BillyJan$1
1BillyFeb$0
1BillyMar$0
2WillyJan$2
2WillyFeb$2
2WillyMar$2
3JillyJan$1
3JillyFeb$1
3JillyMar$1,000,001

 

data start_data;
   input ID $1 Name $3-8 Month $9-11 Money 12-20;
   datalines;
1 Billy Jan 1
1 Billy Feb 1
1 Billy Mar 1
2 Willy Jan 1
2 Willy Feb 1
2 Willy Mar 1
3 Jilly Jan 1
3 Jilly Feb 1
3 Jilly Mar 1
;
run;

data adj_data;
   input ID $1 Month $3-5 Adjustment $6-35;
   datalines;
1 Feb Quit Job
2 Jan Got a Raise
3 Mar Won the Lottery
;
run;

data end_data;
   input ID $1 Name $3-8 Month $9-11 Money 12-20;
   datalines;
1 Billy Jan 1
1 Billy Feb 0
1 Billy Mar 0
2 Willy Jan 2
2 Willy Feb 2
2 Willy Mar 2
3 Jilly Jan 1
3 Jilly Feb 1
3 Jilly Mar 1000001
;
run;

*Rules
1) If you quit your job, you don't get a paycheck for subsequent months
2) If you get a raise, your paycheck increases by $1 for all subsequent months
3) If you win the lottery, you get a one time bonus of $1,000,000;

data end_data_test;
set start_data;
if 0 then set adj_data;
if _n_=1 then do;
	dcl hash adj(dataset:"adj_data");
		adj.definekey("ID","Month");
		adj.definedata("ID","Month","Adjustment");
		adj.definedone();
	declare hiter h("adj_data");
end;
h.first(); *find the first match on the adjustment record;
	if Adjustment = "Quit Job" then do
	Money = 0; *If it is the "Quit Job" adjustment, set the first observation's Money amount to 0;
		do while (adj.find()=0);
			h.next(); *Set all subsequent month's Money amounts to 0 for this ID;
			Money=0;
		end;
	end;
	else if Adjustment = "Got a Raise" then  do
	Money = Money+1;
		do while (adj.find()=0);
			h.next();
			Money=Money+1;
		end;
	end;
	else if Adjustment = "Won the Lottery" then 
	Money = Money+1000000;
	*Here is code for how I would do this if the hash table included adjustments for each
	ID/month combo;
/*rc_adj=adj.find();*/
/*if rc_adj=0 then do;*/
/*	if Adjustment = "Quit Job" then*/
/*	Money = 0;*/
/*	else if Adjustment = "Got a Raise" then */
/*	Money = Money+1;*/
/*	else if Adjustment = "Won the Lottery" then */
/*	Money = Money+1000000;*/
/*	end;*/
/*else Adjustment="";*/

run;
1 ACCEPTED SOLUTION

Accepted Solutions
ScottBass
Rhodochrosite | Level 12

For the example as you have posted, you don't need a hash iterator.  There is no need to iterate over the hash.

 

Try this:

 

options nocenter;

data start_data;
   input ID $1 Name $3-8 Month $9-11 Money 12-20;
   datalines;
1 Billy Jan 1
1 Billy Feb 1
1 Billy Mar 1
2 Willy Jan 1
2 Willy Feb 1
2 Willy Mar 1
3 Jilly Jan 1
3 Jilly Feb 1
3 Jilly Mar 1
;
run;

data adj_data;
   input ID $1 Month $3-5 Adjustment $6-35;
   datalines;
1 Feb Quit Job
2 Jan Got a Raise
3 Mar Won the Lottery
;
run;

data end_data;
   input ID $1 Name $3-8 Month $9-11 Money 12-20;
   datalines;
1 Billy Jan 1
1 Billy Feb 0
1 Billy Mar 0
2 Willy Jan 2
2 Willy Feb 2
2 Willy Mar 2
3 Jilly Jan 1
3 Jilly Feb 1
3 Jilly Mar 1000001
;
run;

data test;
   * set PDV order and attributes ;
   if 0 then set start_data adj_data;

   * note that data set columns have an implied retain, which is what we want here ;
   * retain adjustment;  * you can add this if you wish but it is redundant (comment out and see for yourself) ;
   if (_n_ = 1) then do;
      declare hash _h1 ( dataset: "adj_data ( keep=id month adjustment )" , hashexp: 16 , ordered: "N" );
      _h1.defineKey("id","month");
      _h1.defineData("adjustment");
      _h1.defineDone();
   end;
   set start_data;
   by id;
   if first.id then call missing(adjustment);  * required due to the implied (or explicit) retain ;
   _rc_h1 = _h1.find();
   select(adjustment);
      when('Quit Job')        money=0;
      when('Got a Raise')     money=money+1;
      when('Won the Lottery') money=money+1000000;
      otherwise;
   end;
run;

proc compare base=end_data comp=test;
run;

Please post your question as a self-contained data step in the form of "have" (source) and "want" (desired results).
I won't contribute to your post if I can't cut-and-paste your syntactically correct code into SAS.

View solution in original post

1 REPLY 1
ScottBass
Rhodochrosite | Level 12

For the example as you have posted, you don't need a hash iterator.  There is no need to iterate over the hash.

 

Try this:

 

options nocenter;

data start_data;
   input ID $1 Name $3-8 Month $9-11 Money 12-20;
   datalines;
1 Billy Jan 1
1 Billy Feb 1
1 Billy Mar 1
2 Willy Jan 1
2 Willy Feb 1
2 Willy Mar 1
3 Jilly Jan 1
3 Jilly Feb 1
3 Jilly Mar 1
;
run;

data adj_data;
   input ID $1 Month $3-5 Adjustment $6-35;
   datalines;
1 Feb Quit Job
2 Jan Got a Raise
3 Mar Won the Lottery
;
run;

data end_data;
   input ID $1 Name $3-8 Month $9-11 Money 12-20;
   datalines;
1 Billy Jan 1
1 Billy Feb 0
1 Billy Mar 0
2 Willy Jan 2
2 Willy Feb 2
2 Willy Mar 2
3 Jilly Jan 1
3 Jilly Feb 1
3 Jilly Mar 1000001
;
run;

data test;
   * set PDV order and attributes ;
   if 0 then set start_data adj_data;

   * note that data set columns have an implied retain, which is what we want here ;
   * retain adjustment;  * you can add this if you wish but it is redundant (comment out and see for yourself) ;
   if (_n_ = 1) then do;
      declare hash _h1 ( dataset: "adj_data ( keep=id month adjustment )" , hashexp: 16 , ordered: "N" );
      _h1.defineKey("id","month");
      _h1.defineData("adjustment");
      _h1.defineDone();
   end;
   set start_data;
   by id;
   if first.id then call missing(adjustment);  * required due to the implied (or explicit) retain ;
   _rc_h1 = _h1.find();
   select(adjustment);
      when('Quit Job')        money=0;
      when('Got a Raise')     money=money+1;
      when('Won the Lottery') money=money+1000000;
      otherwise;
   end;
run;

proc compare base=end_data comp=test;
run;

Please post your question as a self-contained data step in the form of "have" (source) and "want" (desired results).
I won't contribute to your post if I can't cut-and-paste your syntactically correct code into SAS.

hackathon24-white-horiz.png

2025 SAS Hackathon: There is still time!

Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!

Register Now

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 1 reply
  • 681 views
  • 2 likes
  • 2 in conversation