BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
sasuser_01
Fluorite | Level 6

 

Dataset1

ProductId Account_Num Flag1 Flag2 Flag3 

1               89123              Y        Y        N

1               98571              N       Y        Y

2                86754              Y       Y         N

 

Dataset2

Product_Id  R_Code Order

1                     50         1

1                      45        2

2                      80        1   

 

In Macros i have  conditions 

 %macro 50;
if Product_Id in ('1') then do ;
if Flag1 in ('Y') then do;
status_code ='50';
end;
end;
%mend 50;

 

 %macro 45;
if Product_Id in ('1') then do ;
if Flag2 in ('Y') then do;
status_code ='45';
end;
end;
%mend 45;

 

Here  for example - acct_num 89123 qualify for status_code 50 and 45 as per the conditions specified in macros. But in output dataset i should only get the status_code to be updated to 50 to this particular account as it's order is 1. We have to get the status_code which is first matching based on order. In the same way all the accounts should get updated with correct status_code.

Output Dataset

Product_id  Account_Num Flag1 Flag2 Flag3 Status_Code

1               89123              Y        Y        N             50

1               98571              N      Y        Y                45

2                86754              Y       Y         N              50

 

Can anyone tell me how to solve this?

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

I don't think you have totally explained what you are doing.

It looks like the second dataset is what is driving the logic.  So let's call that dataset the RULES.

data rules;
  input Product_Id Order R_Code ;
cards;
1 1 50
1 2 45
2 1 80
;

And the first dataset seems to be the actual data.  Let's call that ORDERS.

data orders ;
  input Account_Num Product_Id (Flag1-Flag2) (:$1.);
cards;
89123  1  Y Y 
98571  1  N Y 
86754  2  Y Y 
;

And now reading between the lines of your IF/THEN statements it looks like you want to use the FLAG1 status with the ORDER=1 rule.  So it would be better to transpose the ORDERS dataset to have one observation per FLAG.

data orders_tall;
  set orders;
  array _flag flag1-flag2 ;
  do order=1 to dim(_flag);
     flag=_flag[order];
     output;
  end;
  drop flag1-flag2;
run;

Tom_0-1669489260534.png

Now we can merge the data by PRODUCT_ID and ORDER .

proc sql;
create table want as
  select a.*
       , b.r_code
  from orders_tall a 
  left join rules b
    on a.product_id=b.product_id
    and a.order = b.order 
    and a.flag='Y'
  order by a.account_num,a.product_id,a.order
;
quit;

Tom_1-1669489621036.png

And then roll it back up into a single observation.

data want;
  set want;
  by account_num product_id;
  retain status_code flag1-flag2;
  array _flag $1 flag1-flag2 ;
  length status_code $8 ;
  if first.product_id then call missing(of status_code _flag[*]);
  status_code=coalescec(status_code,r_code);
  _flag[order]=flag;
  if last.product_id;
  drop flag r_code order;
run;

Tom_2-1669489885150.png

 

This can easily be extended from TWO flag/order value to 50.  And no macros (or macro variables) are required.

 

View solution in original post

9 REPLIES 9
PeterClemmensen
Tourmaline | Level 20

How many macro with logic do you have? Why is the logic contained in macros?

sasuser_01
Fluorite | Level 6
That is the requirement. We should keep conditions only in macro. And for every if condition one specific macro should be created.
sasuser_01
Fluorite | Level 6
And there are 50 plus macros .
SASKiwi
PROC Star

So is there are rule that if an account qualifies for more than one status, the highest status code is applied?

 

Also macro names need to be valid SAS names and they can't start with a number.

fja
Lapis Lazuli | Level 10 fja
Lapis Lazuli | Level 10

@sasuser_01 wrote:
And there are 50 plus macros .

And let me guess, they only differ in the value to be compared to? 🙂 Using arguments to macros  wouldn't be allowed?

Astounding
PROC Star

The data you presented show that Product_ID and Flag2 don't exist in the same data set.  How do you propose to put the data together so that a macro could be applied?

 

What do you want to name your macros?  Clearly "50" and "45" are invalid names for a macro?

sasuser_01
Fluorite | Level 6
Dataset 1 has product_id and flag variables. I will call macros in dataset1. And also I will change macros to m50 and m45 etc. My thought is to keep all the updated status codes in a array in output dataset. And then to select the value in an array according to the order mentioned in dataset 2.
fja
Lapis Lazuli | Level 10 fja
Lapis Lazuli | Level 10

I do not fully understand the idea behind your macros and the intended logic. The macros given just act on product_id 1 ... what about the others? What shall be the status_code if the flag tested for is different from Y?

Have I missed something?

--fja

 

edit: To be more precise: Wouldn't simply merging in the first matching observation from dataset2 an alternative to the use of macros (code untested):

data outTable; 
  merge dataset1 dataset2;
  by Product_Id;
  if first.Product_Id = 1;
run;
Tom
Super User Tom
Super User

I don't think you have totally explained what you are doing.

It looks like the second dataset is what is driving the logic.  So let's call that dataset the RULES.

data rules;
  input Product_Id Order R_Code ;
cards;
1 1 50
1 2 45
2 1 80
;

And the first dataset seems to be the actual data.  Let's call that ORDERS.

data orders ;
  input Account_Num Product_Id (Flag1-Flag2) (:$1.);
cards;
89123  1  Y Y 
98571  1  N Y 
86754  2  Y Y 
;

And now reading between the lines of your IF/THEN statements it looks like you want to use the FLAG1 status with the ORDER=1 rule.  So it would be better to transpose the ORDERS dataset to have one observation per FLAG.

data orders_tall;
  set orders;
  array _flag flag1-flag2 ;
  do order=1 to dim(_flag);
     flag=_flag[order];
     output;
  end;
  drop flag1-flag2;
run;

Tom_0-1669489260534.png

Now we can merge the data by PRODUCT_ID and ORDER .

proc sql;
create table want as
  select a.*
       , b.r_code
  from orders_tall a 
  left join rules b
    on a.product_id=b.product_id
    and a.order = b.order 
    and a.flag='Y'
  order by a.account_num,a.product_id,a.order
;
quit;

Tom_1-1669489621036.png

And then roll it back up into a single observation.

data want;
  set want;
  by account_num product_id;
  retain status_code flag1-flag2;
  array _flag $1 flag1-flag2 ;
  length status_code $8 ;
  if first.product_id then call missing(of status_code _flag[*]);
  status_code=coalescec(status_code,r_code);
  _flag[order]=flag;
  if last.product_id;
  drop flag r_code order;
run;

Tom_2-1669489885150.png

 

This can easily be extended from TWO flag/order value to 50.  And no macros (or macro variables) are required.

 

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
  • 9 replies
  • 1217 views
  • 3 likes
  • 6 in conversation