Solved

How can I create SAS macro with parameters?

Posted on 2015-02-04
16
246 Views
Last Modified: 2016-02-13
Hello,
I will not be able to run below program for the next 2-4 days but I am trying to see if my syntax is correct or maybe if this program can be written differently/ in a better way? Any help will be greatly appreciated!  

I am trying to input two SAS datasets (parameters "indata1" and "indata2") and then I am trying to create two SAS datasets (parameters "outdata1" and "outdata2") with using macro. Below are the steps that I am trying to accomplish in order to have a correct output information in my two output datasets:
 
1.  I need to create SAS macro MAINMACRO with three parameters - input dataset ($indata1" and "$indata2"), output dataset ("$outdata1" and "$outdata2"), and type ("typea" and "typeb").

2. .      For every record in input dataset:
  2.1 Calculate the number of input record
  2.2 Assign value to variable "Var5"
      If car1=car1a and car2=car2a and car3=car3a
        then Var5 = 1
       Else If car1=car1a and car2=car2a
        then Var5 = 3
       Else If car1=car1a
         then Var5 = 4
      Else Var5 = 5
 
   2.3 Calculate the counters ("count1", "count3", "count4", and "count5") for each Var5 value (1,3,4,5) and total read_in and write_out.
   2.4. Output to output dataset.

3.      Then write “Assign Var5 value for &type” as title, total number of read_in from input files and total number of write_out to output files and the counters for various value of Var5 to process log file ("process.log").


 %macro MACRO1;
  data _null_;
   set $indata1 $indata2;
   length dsin $16. dsout $17.;

   dsin='outdata.&outdata1;
   dsout='outdata.&outdata2;

   call symput("inset",dsin);
   call symput("outset",dsout);
   call execute('%MACRO2(&inset, &outset)');
  run;
%mend MACRO1;

%macro MACRO2(dsin, dsout);
data var5data;
 set &dsin;
 
 if  car1||car2||car3 = 
     car1a||car2a||car3a  then do;
  Var5 = '1';
 end;
 
 else if car1||car2 = 
            car1a||car2a then do;
   Var5 = '3';
 end;
 
 else if car1 = 
            car1a then do;
   Var5 = '4';
 end;

 else do;
   Var5 = '5';
 end;

   output var5data;
run;

data counts (keep= Var1 Var2 Var3 Va4 Var5 Var6 Var7);
     length count1 count3 count4 count5 count_in count_out; 
     retain count1 count3 count4 count5 count_in count_out;
    count_in = count_in +1;   

 set var5data end=lastrec;

      if Var5 = '1' then count1+1;
      else if Var5 = '3' then count3+1;
      else if Var5 = '4' then count4+1;
      else if Var5 = '5' then count5+1;
      
     count_in= count_out+1; 
      output;
    end;

 if lastrec then
    do;
      file process.log mod;
      put 'Assign Var5 value for &type';
      put 'Total number of records with Var5 = 1: ' count1;
      put 'Total number of records with Var5 = 3: ' count3;
      put 'Total number of records with Var5 = 4: ' count4;
      put 'Total number of records with Var5 = 5: ' count5;
      put 'Total number of records read in:            ' count_in;
      put 'Total number of records read out:         ' count_out;
      put '*****************************************************';  
      put ' ';    
 end;
run;

/* create the permanent dataset */
data &dsout;
  set counts;
run;

%mend MACRO2;

/* Below macro calls the above macros according to value of TYPE */
%macro MAINMACRO;

 /* Run Program for TYPE */ 

%if "&type" = "typea " %then %do;
   %MACRO2("&indata1", "&outdata1", "&typea"); 
 %end;

 %else %if "&type" = "typeb " %then %do;
  %MACRO2("&indata2", "&outdata2", "&typeb"); 
 %end;

%mend MAINMACRO;
%MAINMACRO;

Open in new window


Thank you!
0
Comment
Question by:labradorchik
  • 9
  • 7
16 Comments
 
LVL 14

Expert Comment

by:Aloysius Low
ID: 40590098
I suppose you need help only to achieve point 1 above?

But I've got the following questions
1. What is MACRO1 supposed to achieve?
2. Why do you need to execute MACRO2 within MAINMACRO?
3. Where are the values for DSIN, DSOUT and TYPE coming from i.e. where is the assignment? Are they global variables?

I'm not making sense of your code from your description - something is not right.

Assuming the way you have written your macros is correctly, you need to change it to include 1 more parameter - TYPE - so that it can be passed in from MAINMACRO:
%MACRO MACRO2(DSIN, DSOUT, TYPE);

Then you need to allow macros to be passed into MAINMACRO can call MACRO2 from MAINMACRO as follow:
%MACRO MAINMACRO(DSIN, DSOUT, TYPE);
  %MACRO2(&DSIN, &DSOUT, &TYPE)
%MEND;
But doing this begs my second question above.

Hope you can clarify so that I can help you further.
0
 

Author Comment

by:labradorchik
ID: 40591062
Hello lowaloysius! Thank you very much for your comments!!

Here some background on the program. There is a control script, which has a control panel with selections #1 and #2
#1 is for files with typea
#2 is for files with typeb
   
So every time #1 is selected: this SAS program will be running with &indata1, &outdata1, &typea parameters
And every time #2 is selected: this SAS program will be running with &indata2, &outdata2, &typeb parameters

So every time this SAS program is called from #1 or #2 selection from the script it should choose correct parameters.  The script is already written with its own process and I am just trying to pass these parameters through MAINMACRO with all step 2 and step 3 processes for each input files (indata1 and indata2) that has MACRO2.

Answers to your questions:
3. Yes, all below parameters or logicals are global variables.
indata1, outdata1, typea
indata2, outdata2, typeb

1. I used MACRO1 to read parameters (these are actually SAS datasets) indata1 and indata2 and then create/output to outdata1 and outdata2 parameters (also SAS datatsets).

Note: I already have my two input files (indata1 and indata2) but I am still trying to create my output files (outdata1 and outdata2) so that's why I thought MACRO1 would be necessary before I start with step 2 and 3.

I am just trying to see how can I do all three steps in more efficient way for this program and get my two output files (outdata1 and outdata2) correctly.  

2. I am trying to execute MACRO2 within MAINMACRO because I thought this would be more efficient way since there are two selections in the script (#1 and #2) but I am not sure if my logic is correct. And since I can not test my code yet I am puzzled.

Please let me know if you have any additional questions and I will reply today.
Thank you in advance!
0
 

Author Comment

by:labradorchik
ID: 40592337
I thought about what I said before and I am not sure if all those parameters can be described as global variables, those parameters just passed from a bash script.

I am trying to rewrite my SAS code and see if this will makes any sense.
Please note: all 3 requirements steps are the same


%let typea=%sysget(type);

/*Get needed parameters from script */
%macro getparamtrs;
 data _null_;
   length type $4;
   type="&typea ";
   call symput ("type", type);
  run;
%mend getparamtrs;

%macro MACRO1(indata1, outdata1, typea);
data var5data;
 set "&indata1";
 
 if  car1||car2||car3 = 
     car1a||car2a||car3a  then do;
  Var5 = '1';
 end;
 
 else if car1||car2 = 
            car1a||car2a then do;
   Var5 = '3';
 end;
 
 else if car1 = 
            car1a then do;
   Var5 = '4';
 end;

 else do;
   Var5 = '5';
 end;

   output var5data;
run;

data counts (keep= Var1 Var2 Var3 Va4 Var5 Var6 Var7);
     length count1 count3 count4 count5 count_in count_out; 
     retain count1 count3 count4 count5 count_in count_out;
    count_in = count_in +1;   

 set var5data end=lastrec;

      if Var5 = '1' then count1+1;
      else if Var5 = '3' then count3+1;
      else if Var5 = '4' then count4+1;
      else if Var5 = '5' then count5+1;
      
     count_in= count_out+1; 
      output;
    end;

 if lastrec then
    do;
      file process.log mod;
      put 'Assign Var5 value for &type';
      put 'Total number of records with Var5 = 1: ' count1;
      put 'Total number of records with Var5 = 3: ' count3;
      put 'Total number of records with Var5 = 4: ' count4;
      put 'Total number of records with Var5 = 5: ' count5;
      put 'Total number of records read in:            ' count_in;
      put 'Total number of records read out:         ' count_out;
      put '*****************************************************';  
      put ' ';    
 end;
run;

 /* create the permanent dataset */
 data &outdata1;
   set counts;
 run;
%mend MACRO1;

%macro MACRO2(indata2, outdata2, typeb);
data var5data;
 set "&indata2";
 
 if  car1||car2||car3 = 
     car1a||car2a||car3a  then do;
  Var5 = '1';
 end;
 
 else if car1||car2 = 
            car1a||car2a then do;
   Var5 = '3';
 end;
 
 else if car1 = 
            car1a then do;
   Var5 = '4';
 end;

 else do;
   Var5 = '5';
 end;

   output var5data;
run;

data counts (keep= Var1 Var2 Var3 Va4 Var5 Var6 Var7);
     length count1 count3 count4 count5 count_in count_out; 
     retain count1 count3 count4 count5 count_in count_out;
    count_in = count_in +1;   

 set var5data end=lastrec;

      if Var5 = '1' then count1+1;
      else if Var5 = '3' then count3+1;
      else if Var5 = '4' then count4+1;
      else if Var5 = '5' then count5+1;
      
     count_in= count_out+1; 
      output;
    end;

 if lastrec then
    do;
      file process.log mod;
      put 'Assign Var5 value for &type';
      put 'Total number of records with Var5 = 1: ' count1;
      put 'Total number of records with Var5 = 3: ' count3;
      put 'Total number of records with Var5 = 4: ' count4;
      put 'Total number of records with Var5 = 5: ' count5;
      put 'Total number of records read in:            ' count_in;
      put 'Total number of records read out:         ' count_out;
      put '*****************************************************';  
      put ' ';    
 end;
run;

 /* create the permanent dataset */
 data &outdata2;
   set counts;
 run;
%mend MACRO2;

/* Below macro calls the above macros according to value of TYPE */
%macro MAINMACRO;
 %getparamtrs;

 /* Run Program for TYPE */ 
%if "&type" = "typea " %then %do;
 %let type = typea;
   %MACRO1("&indata1", "&outdata1", "&typea"); 
 %end;

 %else %if "&type" = "typeb " %then %do;
 %let type = typeb;
  %MACRO2("&indata2", "&outdata2", "&typeb"); 
 %end;

%mend MAINMACRO;
%MAINMACRO;

Open in new window


Please let me know if you know any easier or efficient way to accomplish all 3 requirements steps. Maybe all code can be placed in just one macro?
0
 
LVL 14

Expert Comment

by:Aloysius Low
ID: 40592690
My opinion is that there's no need for MACRO1 and MACRO2. The codes are essentially the same, except for the variables, which is already being passed into the macro in the first place. Thus, there's really no need to duplicate the macros.

What you need to do is to write a macro with a generic code, which then also means that there's no need for a separate macro. MAINMACRO is sufficient, and it replaces MACRO1 and MACRO2. And to make it compliant with your point 1, it should have 3 parameters. I would write it as thus:

%macro MAINMACRO(indata, outdata, type);
data var5data;
 set &indata;
 
 if  car1||car2||car3 = 
     car1a||car2a||car3a  then do;
  Var5 = '1';
 end;
 
 else if car1||car2 = 
            car1a||car2a then do;
   Var5 = '3';
 end;
 
 else if car1 = 
            car1a then do;
   Var5 = '4';
 end;

 else do;
   Var5 = '5';
 end;

   output var5data;
run;

data counts (keep= Var1 Var2 Var3 Va4 Var5 Var6 Var7);
     length count1 count3 count4 count5 count_in count_out; 
     retain count1 count3 count4 count5 count_in count_out;
    count_in = count_in +1;   

 set var5data end=lastrec;

      if Var5 = '1' then count1+1;
      else if Var5 = '3' then count3+1;
      else if Var5 = '4' then count4+1;
      else if Var5 = '5' then count5+1;
      
     count_in= count_out+1; 
      output;
    end;

 if lastrec then
    do;
      file process.log mod;
      put "Assign Var5 value for &type";
      put 'Total number of records with Var5 = 1: ' count1;
      put 'Total number of records with Var5 = 3: ' count3;
      put 'Total number of records with Var5 = 4: ' count4;
      put 'Total number of records with Var5 = 5: ' count5;
      put 'Total number of records read in:            ' count_in;
      put 'Total number of records read out:         ' count_out;
      put '*****************************************************';  
      put ' ';    
 end;
run;

 /* create the permanent dataset */
 data &outdata;
   set counts;
 run;
%mend;

Open in new window

Note that I have removed quotation marks around indata1 (which I have changed it to indata to align with the macro parameters).
Also note that I have changed the quotation marks surrounding &type to that of double quotation marks instead of single quotation marks as SAS will treat them as literal values instead of variables.

One thing I have not tried before is the assignment of variables from batch scripts. I know it can work but I'm not sure how. So I'm assuming that the %sysget gets the job done, and going by what you have said, the parameters come in from a batch script, I'm taking it as all 3 values comes from the script. In which case, you just need to do:
%let type=%sysget(type);
%let indata=%sysget(indata);
%let outdata=%sysget(outdata);

Open in new window


And there is no further need for the macro GETPARAMTRS.

Your main execution code would thus be just
%MAINMACRO(&indata, &outdata, &type);

Open in new window

0
 

Author Comment

by:labradorchik
ID: 40592862
Thank you very much for your comments!!

I think having just one macro makes sense to me now just one thing. Since there are 6 in total parameters that are passed from the Unix bash script to this SAS program, so how would I implement all 6 parameters in just one macro?

6 parameters are:
indata1, outdata1, typea
and
indata2, outdata2, typeb

Note about these parameters: indata1 and indata2 are input SAS datasets and outdata1 and outdata2 are output SAS datasets.
typea and typeb are just variables for different type of selection based on the content of datasets.
0
 
LVL 14

Expert Comment

by:Aloysius Low
ID: 40592993
Wait - you mean there's 6 parameters coming in?? I was under the impression there'd be one set of 3!

But in any case, you could call the macro twice? Like
%let type=%sysget(typea);
%let indata=%sysget(indata1);
%let outdata=%sysget(outdata1);
%MAINMACRO(&indata, &outdata, &type);

%let type=%sysget(typeb);
%let indata=%sysget(indata2);
%let outdata=%sysget(outdata2);
%MAINMACRO(&indata, &outdata, &type);

Open in new window

0
 

Author Comment

by:labradorchik
ID: 40593386
Thank you very much!

Great! I will have just one MAINMACRO but I will call it twice as below:

%let type=%sysget(typea);
%let indata=%sysget(indata1);
%let outdata=%sysget(outdata1);
%MAINMACRO(&indata, &outdata, &type);

%let type=%sysget(typeb);
%let indata=%sysget(indata2);
%let outdata=%sysget(outdata2);
%MAINMACRO(&indata, &outdata, &type);

%macro MAINMACRO(indata, outdata, type);
data var5data;
 set &indata;
 
 if  car1||car2||car3 = 
     car1a||car2a||car3a  then do;
  Var5 = '1';
 end;
 
 else if car1||car2 = 
            car1a||car2a then do;
   Var5 = '3';
 end;
 
 else if car1 = 
            car1a then do;
   Var5 = '4';
 end;

 else do;
   Var5 = '5';
 end;

   output var5data;
run;

data counts (keep= Var1 Var2 Var3 Va4 Var5 Var6 Var7);
     length count1 count3 count4 count5 count_in count_out; 
     retain count1 count3 count4 count5 count_in count_out;
    count_in = count_in +1;   

 set var5data end=lastrec;

      if Var5 = '1' then count1+1;
      else if Var5 = '3' then count3+1;
      else if Var5 = '4' then count4+1;
      else if Var5 = '5' then count5+1;
      
     count_in= count_out+1; 
      output;
    end;

 if lastrec then
    do;
      file process.log mod;
      put "Assign Var5 value for &type";
      put 'Total number of records with Var5 = 1: ' count1;
      put 'Total number of records with Var5 = 3: ' count3;
      put 'Total number of records with Var5 = 4: ' count4;
      put 'Total number of records with Var5 = 5: ' count5;
      put 'Total number of records read in:            ' count_in;
      put 'Total number of records read out:         ' count_out;
      put '*****************************************************';  
      put ' ';    
 end;
run;

 /* create the permanent dataset */
 data &outdata;
   set counts;
 run;
%mend;

Open in new window


I will run above code this upcoming Monday and let you know how it went.

One more question: could you please see if the logic of count_in and count_out are correct? In this program I am trying to calculate counters for "count1, count3, count4, and count5 for each Var5 value and total count_in and count_out for each of two output datasets.

Thank you!
0
 
LVL 14

Accepted Solution

by:
Aloysius Low earned 500 total points
ID: 40593958
length count1 count3 count4 count5 count_in count_out; >> You need to define a number between 3 & 8 for the length - this should give you an error

having
count_in = count_in +1;  
above the set statement would cause it to be executed once only, compared to having it after the set statement, which will execute for every record

also, count_in is not initialized, so if you try to do count_in = count_in + 1, you will always end up with NULL.. you can choose to either initialize it first using the _N_ auto variable, but only after the set statement i.e.
if _N_ = 1 then count_in = 1; else count_in = count_in + 1;
OR
use the sum function:
count_in = sum(count_in, 1);

similarly, you might have problems for the count1, count3, count4 and count5 variables

there's a logic error in doing
count_in= count_out+1;
i believe you are trying to count the number of output records? it should look like
count_out = count_out + 1;
instead?

in fact, since you are not dropping or adding any records while processing them, the number of records input and output should be the same. However, if it is a requirement to have a count of the number of records input and output, it might be better to perform a count separately..

along lines 50-51 of your latest code above, there's a problem:
      output; << there's no need for output statement here. in fact, i'm reading the question differently. i feel that the question is not meant to ask you to perform the steps in sequence, but to achieve the following outcomes. therefore, the computation of the counts can be done within the same data step
    end; << there's no matching do statement.

quite a long list of issues so i'll summarize it using the code snippet here - you can fill in the blanks below which i have deliberately left behind
%macro MAINMACRO(indata, outdata, type);
data &output;
 set &indata end=lastrec;
   << DO YOUR COUNT_IN here >>

 if  car1||car2||car3 = 
     car1a||car2a||car3a  then do;
  Var5 = '1';
  << DO YOUR COUNT1 here >>
 end;
 
 else if car1||car2 = 
            car1a||car2a then do;
   Var5 = '3';
  << DO YOUR COUNT3 here >>
 end;
 
 else if car1 = 
            car1a then do;
   Var5 = '4';
  << DO YOUR COUNT4 here >>
 end;

 else do;
   Var5 = '5';
   << DO YOUR COUNT5 here >>
end;

  << DO YOUR COUNT_OUT here >>

 if lastrec then
    do;
      file process.log mod;
      put "Assign Var5 value for &type";
      put 'Total number of records with Var5 = 1: ' count1;
      put 'Total number of records with Var5 = 3: ' count3;
      put 'Total number of records with Var5 = 4: ' count4;
      put 'Total number of records with Var5 = 5: ' count5;
      put 'Total number of records read in:            ' count_in;
      put 'Total number of records read out:         ' count_out;
      put '*****************************************************';  
      put ' ';    
 end;
run;

Open in new window


i have also deliberately left out some codes which you have written above and is required to complete the picture ;)

more importantly, i hope i've understood you correctly, otherwise, the code above needs to be changed!
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:labradorchik
ID: 40594200
Wow  
Thank you very much for all your comments!!
Yes, you are correct! It should be
count_out = count_out + 1;
Although, both count_in and count_out should be the same in this scenario but I still would like to count both counts separately.

I don't think I have ever wrote this kind of counts process in just one data step but I think now I see what you mean. This really can be very efficient since both of my input files (indata1 and indata2)  have data with running over 2 hours. I am also amazed that I can just use one macro to accomplish all steps for this program!

I added your suggestions in the code below but I am still not sure if count_out = count_out + 1; will work correctly?

%macro MAINMACRO(indata, outdata, type);
data &output;
 set &indata end=lastrec;

    if _N_ = 1 then count_in = 1; 
      else count_in = count_in + 1;

 if  car1||car2||car3 = 
     car1a||car2a||car3a  then do;
  Var5 = '1';
   if _N_ = 1 then count1 = 1; 
      else count1 = count1 + 1;
 end;
 
 else if car1||car2 = 
            car1a||car2a then do;
   Var5 = '3';
   if _N_ = 1 then count3 = 1; 
      else count3 = count3 + 1;
 end;
 
 else if car1 = 
            car1a then do;
   Var5 = '4';
   if _N_ = 1 then count4 = 1; 
      else count4 = count4 + 1;
 end;

 else do;
   Var5 = '5';
    if _N_ = 1 then count5 = 1; 
      else count5 = count5 + 1;
end;

   count_out = count_out + 1;

 if lastrec then
    do;
      file process.log mod;
      put "Assign Var5 value for &type";
      put 'Total number of records with Var5 = 1: ' count1;
      put 'Total number of records with Var5 = 3: ' count3;
      put 'Total number of records with Var5 = 4: ' count4;
      put 'Total number of records with Var5 = 5: ' count5;
      put 'Total number of records read in:            ' count_in;
      put 'Total number of records read out:         ' count_out;
      put '*****************************************************';  
      put ' ';    
 end;
run;

Open in new window

0
 
LVL 14

Expert Comment

by:Aloysius Low
ID: 40595245
not exactly correct..

_N_ = 1 means first record.. u can't possibly have Var5 = 1, Var5 = 3, Var5 = 4 and Var5 = 5 all on the same first record right?

it should look like:
if _N_ = 1 then do;
  count_in = 0;
  count1 = 0;
  count3 = 0;
  count4 = 0;
  count5 = 0;
  count_out = 0;
end;

Open in new window

This will initialize all variables to 0.

Then subsequently, you can do count_in = count_in + 1; and count_out = count_out + 1;

And don't forget to include your retain statement (hint: retain count_in count_out count1 count3 count4 count5;) or your counts will not be correct.

And I suppose you forgot to include the %mend in your code above, but actually have it in your actual code?

Otherwise, it *should* be OK.
0
 

Author Comment

by:labradorchik
ID: 40595619
Thank you, lowaloysius!
You are correct, I forgot to initialize all variables to 0.  Would I need to include the length statement as well before the retain statement and define the number from 3 to 8 for the length ?

%let type=%sysget(typea);
%let indata=%sysget(indata1);
%let outdata=%sysget(outdata1);
%MAINMACRO(&indata, &outdata, &type);

%let type=%sysget(typeb);
%let indata=%sysget(indata2);
%let outdata=%sysget(outdata2);
%MAINMACRO(&indata, &outdata, &type);

%macro MAINMACRO(indata, outdata, type);
data &output;
  retain count1 count3 count4 count5 count_in count_out;

 set &indata end=lastrec;

   if _N_ = 1 then do;
      count_in = 0;
      count1 = 0;
      count3 = 0;
      count4 = 0;
      count5 = 0;
      count_out = 0;
   end;

count_in = count_in + 1;

 if  car1||car2||car3 = 
     car1a||car2a||car3a  then do;
  Var5 = '1'; 
      count1 = count1 + 1;
 end;
 
 else if car1||car2 = 
            car1a||car2a then do;
   Var5 = '3';
      count3 = count3 + 1;
 end;
 
 else if car1 = 
            car1a then do;
   Var5 = '4';
      count4 = count4 + 1;
 end;

 else do;
   Var5 = '5';
      count5 = count5 + 1;
 end;

      count_out = count_out + 1;

 if lastrec then
    do;
      file process.log mod;
      put "Assign Var5 value for &type";
      put 'Total number of records with Var5 = 1: ' count1;
      put 'Total number of records with Var5 = 3: ' count3;
      put 'Total number of records with Var5 = 4: ' count4;
      put 'Total number of records with Var5 = 5: ' count5;
      put 'Total number of records read in:            ' count_in;
      put 'Total number of records read out:         ' count_out;
      put '*****************************************************';  
      put ' ';    
 end;
run;
%mend;

Open in new window


Is there way to write just one if-else-end statement for counts 1, 3, 4 and 5?
0
 
LVL 14

Expert Comment

by:Aloysius Low
ID: 40595650
length statement is optional. if it's there, SAS will use what you defined; if it isn't, SAS will default the length to 8.

i don't see any other way about writing the if-else statements - that's how i'd do it too!
0
 

Author Comment

by:labradorchik
ID: 40595725
Great! Thank you so much!!
I will test above code this Monday and let you know what errors if any I will get. I just hope code works well.

Have a great weekend!
0
 

Author Comment

by:labradorchik
ID: 40599209
I think my macro is not defined correctly or my macro logic is not correct.  
I have run below SAS code multiple times today and keep getting the following Warning in my sas.log file:
The argument to macro function %SYSGET is not defined as a system variable.
%MAINMACRO("&indata", "&outdata", "&type");
   
following by an another Warning:
Apparent invocation of macro MAINMACRO not resolved.

and then Error:
% in %MAINMACRO - Statement is not valid or it is used out of proper order.

So,  when I am running the below script, which invokes below SAS code, I am not outputting my two output SAS datasets (OUTDATA1 and OUTDATA2) and none of counters are written to the process.log when MAINMACRO macro is running. Actually, I am not even sure if macro runs at all. Maybe SAS code stops processing before even it gets to MAINMACRO macro?

My Unix bash script
#!/bin/bash
export INDATA1=/maindir/mydir/myindata1.sas7bdat 
export OUTDATA1=/maindir/mydir/myoutdata1.sas7bdat 
export INDATA2=/maindir/mydir/myindata2.sas7bdat 
export OUTDATA2=/maindir/mydir/myoutdata2.sas7bdat 
export type="typea " 
export type="typeb "

$sas mysascode.sas

Open in new window


My SAS code
%let type=%sysget(typea);
%let indata=%sysget(INDATA1);
%let outdata=%sysget(OUTDATA1);
%MAINMACRO("&indata", "&outdata", "&type");

%let type=%sysget(typeb);
%let indata=%sysget(INDATA2);
%let outdata=%sysget(OUTDATA2);
%MAINMACRO("&indata", "&outdata", "&type");

%macro MAINMACRO(indata, outdata, type);
data "&oudata";
  retain count1 count3 count4 count5 count_in count_out;

 set "&indata" end=lastrec;

   if _N_ = 1 then do;
      count_in = 0;
      count1 = 0;
      count3 = 0;
      count4 = 0;
      count5 = 0;
      count_out = 0;
   end;

count_in = count_in + 1;

 if  car1||car2||car3 = 
     car1a||car2a||car3a  then do;
  Var5 = '1'; 
      count1 = count1 + 1;
 end;
 
 else if car1||car2 = 
            car1a||car2a then do;
   Var5 = '3';
      count3 = count3 + 1;
 end;
 
 else if car1 = 
            car1a then do;
   Var5 = '4';
      count4 = count4 + 1;
 end;

 else do;
   Var5 = '5';
      count5 = count5 + 1;
 end;

      count_out = count_out + 1;

 if lastrec then
    do;
      file dir.process.log mod;
      put "Assign Var5 value for &type";
      put 'Total number of records with Var5 = 1: ' count1;
      put 'Total number of records with Var5 = 3: ' count3;
      put 'Total number of records with Var5 = 4: ' count4;
      put 'Total number of records with Var5 = 5: ' count5;
      put 'Total number of records read in:            ' count_in;
      put 'Total number of records read out:         ' count_out;
      put '*****************************************************';  
      put ' ';    
 end;
run;
%mend;

Open in new window


I tried different ways of using below line of code with no quotes, single quotes, and double quotes as below but I still receive below Warming each time:
The argument to macro function %SYSGET is not defined as a system variable.

%MAINMACRO("&indata", "&outdata", "&type");

Open in new window


Please let me know if you have any comments or suggestions. I really can not figure out what I am defining incorrectly. I thought I defined variables correctly in the Unix shell script.
0
 

Author Comment

by:labradorchik
ID: 40599892
I had to create a second macro, so all parameters would go through MAINMACRO macro. Still in testing but I am already getting my two output files and process.log with all counts.  

Thank you very much,  lowaloysius!
Your comments and suggestions really helped!!

%macro MAINMACRO(ind, outd, tp);
data "&oud";
  retain count1 count3 count4 count5 count_in count_out;

 set "&ind" end=lastrec;

   if _N_ = 1 then do;
      count_in = 0;
      count1 = 0;
      count3 = 0;
      count4 = 0;
      count5 = 0;
      count_out = 0;
   end;

count_in = count_in + 1;

 if  car1||car2||car3 = 
     car1a||car2a||car3a  then do;
  Var5 = '1'; 
      count1 = count1 + 1;
 end;
 
 else if car1||car2 = 
            car1a||car2a then do;
   Var5 = '3';
      count3 = count3 + 1;
 end;
 
 else if car1 = 
            car1a then do;
   Var5 = '4';
      count4 = count4 + 1;
 end;

 else do;
   Var5 = '5';
      count5 = count5 + 1;
 end;

      count_out = count_out + 1;

 if lastrec then
    do;
      file dir.process.log mod;
      put 'Assign Var5 value for ' "&tp";
      put 'Total number of records with Var5 = 1: ' count1;
      put 'Total number of records with Var5 = 3: ' count3;
      put 'Total number of records with Var5 = 4: ' count4;
      put 'Total number of records with Var5 = 5: ' count5;
      put 'Total number of records read in:            ' count_in;
      put 'Total number of records read out:         ' count_out;
      put '*****************************************************';  
      put ' ';    
 end;
run;
%mend;

%macro final;
%let type=%sysget(type1);
%if "&type" = "typea" %then %do;
%let indata=%sysget(INDATA1);
%let outdata=%sysget(OUTDATA1);
%MAINMACRO("&indata", "&outdata", "&type");
%end;

%let type=%sysget(type1);
%if "&type" = "typeb" %then %do;
%let indata=%sysget(INDATA2);
%let outdata=%sysget(OUTDATA2);
%MAINMACRO("&indata", "&outdata", "&type");
%end;

%mend;
%final;

Open in new window

0
 
LVL 14

Expert Comment

by:Aloysius Low
ID: 40599931
glad to be of help, though i'm not able to help much with the last bit regarding passing of input parameters from ksh as i've never done this before.

on a separate note, i still think that there's no need to duplicate the assignment of variables although it might be necessary to have another wrapping macro..

in theory, the following should work as fine..
%macro final;
%let type=%sysget(type1);
%let indata=%sysget(INDATA1);
%let outdata=%sysget(OUTDATA1);
%MAINMACRO("&indata", "&outdata", "&type");

%let type=%sysget(type1);
%let indata=%sysget(INDATA2);
%let outdata=%sysget(OUTDATA2);
%MAINMACRO("&indata", "&outdata", "&type");
%mend;

Open in new window


Also, i'm not sure about the usage of double quotation marks surrounding &indata, &outdata and &type, both in the macro call as well as within MAINMACRO itself.. but if it works, that's great :)
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

I annotated my article on ransomware somewhat extensively, but I keep adding new references and wanted to put a link to the reference library.  Despite all the reference tools I have on hand, it was not easy to find a way to do this easily. I finall…
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
An introduction to basic programming syntax in Java by creating a simple program. Viewers can follow the tutorial as they create their first class in Java. Definitions and explanations about each element are given to help prepare viewers for future …
Video by: Steve
Using examples as well as descriptions, step through each of the common simple join types, explaining differences in syntax, differences in expected outputs and showing how the queries run along with the actual outputs based upon a simple set of dem…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now