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

I am writing a bigger script and basically need the following principles to work which I demonstrate by two examples (demonstrating different concepts):

Example 1. Depending on the positional argument, I want to set different data sets: 

%macro MyFun2(random); 
	data MyData; 
		if &random. = AA then do; 
			set sashelp.cars(obs=2);
		end; 
		else if &random. = BB then do; 
			set sashelp.cars(obs=3);
		end; 
	run; 
%mend MyFun2;

%MyFun2(AA);  
%MyFun2(BB);  

Result is: 

SasStatistics_0-1624001780542.png

Notice how the two first columns are created. 

One message in the log is related to "Uninitialized variable" which I read about here http://statskom.com/sas-tips-tricks-9-note-variable-x-is-uninitialized/ . Nevertheless, I am not fully sure of how to handle it properly. 

 

Example 2. Depending on the positional argument, I want to create a new column taking different values: 

Notice the comment in the code below, it is obivously wrong but I don't know how to handle it properly. 

 

%macro MyFun3(random); 
	data MyData; 
		set sashelp.cars(obs=2);
			if &random. = AA then NewCol = 'AA'; 

			else if &random. = BB then NewCol = 'BB';

			else NewCol = "Write something valid"; *This is obiviously wrong, but I would somehow like to do: if &random. is not equal to AA or BB, then assign the value "Write something valid" to NewColumn.;
	run;  
%mend MyFun3;

%MyFun3(AA);  
%MyFun3(BB);  
%MyFun3(Test);

 

The code does not run, I don't write the log since the code can be easily reproduced. 

 

 

I hope it is clear of what I want to achieve. All advice of how to properly do what I want is appreciated. 

1 ACCEPTED SOLUTION

Accepted Solutions
yabwon
Onyx | Level 15

Hi, 

 

@1) Maxim No. 1 says: "Read the log".  Log says:

1    %macro MyFun2(random);
2      data MyData;
3        if &random. = AA then do;
4          set sashelp.cars(obs=2);
5        end;
6        else if &random. = BB then do;
7          set sashelp.cars(obs=3);
8        end;
9      run;
10   %mend MyFun2;
11
12   %MyFun2(AA);

NOTE: Variable AA is uninitialized.
NOTE: Variable BB is uninitialized.
NOTE: There were 2 observations read from the data set SASHELP.CARS.
NOTE: The data set WORK.MYDATA has 2 observations and 17 variables.
NOTE: DATA statement used (Total process time):
      real time           0.09 seconds
      cpu time            0.03 seconds


13   %MyFun2(BB);

NOTE: Variable BB is uninitialized.
NOTE: Variable AA is uninitialized.
NOTE: There were 2 observations read from the data set SASHELP.CARS.
NOTE: The data set WORK.MYDATA has 2 observations and 17 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.01 seconds

Modify your code the following way:

%macro MyFun2(random); 
	data MyData; 
		%if &random. = AA %then %do; 
			set sashelp.cars(obs=2);
		%end; 
		%else %if &random. = BB %then %do; 
			set sashelp.cars(obs=3);
		%end; 
	run; 
%mend MyFun2;

%MyFun2(AA);  
%MyFun2(BB);

Log will be clean and if you add `mprint` option you will see the code of data step that was executed.

 

@2)  The same, read the log. 

Modify your code for example like that:

%macro MyFun3(random); 
	data MyData; 
		set sashelp.cars(obs=2);

      length NewCol $ 30;

			if "&random." = "AA" then NewCol = 'AA'; 

			else if "&random." = "BB" then NewCol = 'BB';

			else 
        do;
        if _N_ = 1 then put "WARNING: Write something valid";
        NewCol = "Write something valid"; /*This is obiviously wrong, but I would somehow like to do: if &random. is not equal to AA or BB, then assign the value "Write something valid" to NewColumn.;*/
        end;
	run;  
%mend MyFun3;

%MyFun3(AA);  
%MyFun3(BB);  
%MyFun3(Test);

 

All the best

Bart

 

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



View solution in original post

12 REPLIES 12
yabwon
Onyx | Level 15

Hi, 

 

@1) Maxim No. 1 says: "Read the log".  Log says:

1    %macro MyFun2(random);
2      data MyData;
3        if &random. = AA then do;
4          set sashelp.cars(obs=2);
5        end;
6        else if &random. = BB then do;
7          set sashelp.cars(obs=3);
8        end;
9      run;
10   %mend MyFun2;
11
12   %MyFun2(AA);

NOTE: Variable AA is uninitialized.
NOTE: Variable BB is uninitialized.
NOTE: There were 2 observations read from the data set SASHELP.CARS.
NOTE: The data set WORK.MYDATA has 2 observations and 17 variables.
NOTE: DATA statement used (Total process time):
      real time           0.09 seconds
      cpu time            0.03 seconds


13   %MyFun2(BB);

NOTE: Variable BB is uninitialized.
NOTE: Variable AA is uninitialized.
NOTE: There were 2 observations read from the data set SASHELP.CARS.
NOTE: The data set WORK.MYDATA has 2 observations and 17 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.01 seconds

Modify your code the following way:

%macro MyFun2(random); 
	data MyData; 
		%if &random. = AA %then %do; 
			set sashelp.cars(obs=2);
		%end; 
		%else %if &random. = BB %then %do; 
			set sashelp.cars(obs=3);
		%end; 
	run; 
%mend MyFun2;

%MyFun2(AA);  
%MyFun2(BB);

Log will be clean and if you add `mprint` option you will see the code of data step that was executed.

 

@2)  The same, read the log. 

Modify your code for example like that:

%macro MyFun3(random); 
	data MyData; 
		set sashelp.cars(obs=2);

      length NewCol $ 30;

			if "&random." = "AA" then NewCol = 'AA'; 

			else if "&random." = "BB" then NewCol = 'BB';

			else 
        do;
        if _N_ = 1 then put "WARNING: Write something valid";
        NewCol = "Write something valid"; /*This is obiviously wrong, but I would somehow like to do: if &random. is not equal to AA or BB, then assign the value "Write something valid" to NewColumn.;*/
        end;
	run;  
%mend MyFun3;

%MyFun3(AA);  
%MyFun3(BB);  
%MyFun3(Test);

 

All the best

Bart

 

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



tarheel13
Rhodochrosite | Level 12
You have to put % before the if and then and the do. Also try mprint mlogic and symbolgen for debugging.
PaigeMiller
Diamond | Level 26

@SasStatistics 

 

%IF and IF (without the %) do not do the same thing.

 

%IF tests the value of macro variables.

IF tests the value of data step variables.

 

When you write macro code, or code involving macro variables, you need to ask yourself if you are testing the value of a macro variable, or testing the value of a data step variable, to be sure you have the right one (%IF or IF).

 

Let's look at your Example 1. Are you trying to test the value of a macro variable, or a data step variable? What is your answer?

--
Paige Miller
SasStatistics
Pyrite | Level 9

Thank you, it clarified things very much. 

Now this is really weird to me: 

In the code below, I use for instance %IF since I am testing a macro variable. 

 

 

%macro MyFun3(random); 
	data MyData; 
		set sashelp.cars(obs=2);
      	length NewCol $ 30;

			%if &random. = "AA" %then NewCol = 'AA'; 
			%else %if &random. = "BB" %then NewCol = 'BB';
			%else %do;
       			 *if _N_ = 1 then put "WARNING: Write something valid"; * Removed this from an solution suggestion since I don't fully understand it yet. ; 
        		NewCol = "Write something valid"; 
        	%end;
	run;  
%mend MyFun3;

%MyFun3(AA);  

This code yields the result: 

 

SasStatistics_0-1624044584869.png

As seen from the red box, it does not accept AA as the argument I was thinking of it to be. 

The right thing to do (As indicated in the answers above) would be to write the code: 

%macro MyFun3(random); 
	data MyData; 
		set sashelp.cars(obs=2);
      	length NewCol $ 30;

			if "&random." = "AA" then NewCol = 'AA'; 
			else if "&random." = "BB" then NewCol = 'BB';
			else do;
       			 *if _N_ = 1 then put "WARNING: Write something valid";
        		NewCol = "Write something valid"; 
        	end;
	run;  
%mend MyFun3;

So now we for instance have 

"&random."

which is seen as a string rather than a macro? I could understand this with "Back-engineering" (understanding it given the solution) but would have big trouble coming up with it myself? 

Why is the first code wrong? 


Thanks. 

 

 

 

yabwon
Onyx | Level 15

Your code should be like this:

%macro MyFun3(random); 
	data MyData; 
		set sashelp.cars(obs=2);
      	length NewCol $ 30;

			%if &random. = AA %then 
        %do; 
          NewCol = 'AA'; 
        %end;
			%else %if &random. = BB %then 
        %do;
          NewCol = 'BB';
        %end;
			%else 
        %do;
          /*if _N_ = 1 then put "WARNING: Write something valid"; * Removed this from an solution suggestion since I don't fully understand it yet. ; */
          NewCol = "Write something valid"; 
       	%end;
	run;  
%mend MyFun3;

%MyFun3(AA);

From macro language perspective _every_ value is a text so quotes are unnecessary.

To test if value of macro variable X is ABC you just write:

%if &X. = ABC %then...

Quotes are necessary on the 4GL language level, because you want to inform compilator that value `AB` is in fact a string text ("AB") an not a variable name (AB)

 

All the best

Bart

 

P.S. Always, always, always use block comments ( /* comment */) in macros.

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



tarheel13
Rhodochrosite | Level 12
options minoperator mprint mlogic symbolgen;
%macro MyFun3(random) / minoperator; 
	data MyData; 
		set sashelp.cars(obs=2);
			%if &random. in (AA BB) %then %do;
			NewCol ="&random";
			%end;
			%else %do;
			NewCol="Write something valid";
			%end;
	run;  
	
	proc print data=mydata;
	run;
%mend MyFun3;

%MyFun3(AA);  
%MyFun3(BB);  
%MyFun3(Test);

You can use minoperator. Also, you don't need to hardcode 'AA' and 'BB' if it's the same as the value of &random.

mkeintz
PROC Star

@Kurt_Bremser wrote:

@yabwon wrote:

Hi, 

 

@1) Maxim No. 1 says: "Read the log".


It's actually Maxim 2 😉


@Kurt_Bremser , @yabwon 

 

🤔 So maybe it's time for

   Maxim 0:  Read the maxim's.

 

 

--------------------------
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

--------------------------
yabwon
Onyx | Level 15

@mkeintz wrote:

@Kurt_Bremser wrote:

@yabwon wrote:

Hi, 

 

@1) Maxim No. 1 says: "Read the log".


It's actually Maxim 2 😉


@Kurt_Bremser , @yabwon 

 

🤔 So maybe it's time for

   Maxim 0:  Read the maxim's.

Good point Mark (@mkeintz)! 👍

Sorry Kurt (@Kurt_Bremser) I was quoting off the top of my head. 🤓

 

All the best

Bart

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



mkeintz
PROC Star

You've received good advice on understanding the difference between %if and if  (and %then vs then%do vs do%end vs end) in macro coding.

 

Below, I suggest another consideration in writing and using macros: avoid code duplication - a major benefit of good macro coding.  In the case of Example 1, you have two instances of a DATA step, which vary only in the SET statement.

 

So instead, in your macro code, make a new macro variable DSN, as follows (which also eliminates the need for %do and %end).

 

 

%macro MyFun(random); 
   %local dsn ;
   %if       &random. = AA %then %let dsn=sashelp.cars(obs=2);
   %else %if &random. = BB %then %let dsn=sashelp.cars(obs=3);
   %else %goto eom ;
  data MyData; 
    set &dsn ;
  run; 
%eom: %mend MyFun2;

options mprint;
%MyFun2(AA);  
%MyFun2(BB);

 

 

This is especially useful if the embedded DATA step is long - needless duplication creates more chances for error, and makes code maintenance more difficult.  

--------------------------
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

--------------------------
SasStatistics
Pyrite | Level 9
Thanks. What is eom in this case doing?
Kurt_Bremser
Super User

Take a step back and internalize these sentences:

"The macro language is a code generator that does its work before any code is actually executed"

"The macro language has one data type only: TEXT"

From this, you will get the answers to your questions.

From the first, you get that you can never access the values of data step/dataset variables in a macro statement.

From the second sentence, you get that no quotes are needed, they are actually part of the "data" (text).

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

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.

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
  • 12 replies
  • 1077 views
  • 11 likes
  • 6 in conversation