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

Here's what I'm currently doing, which is tedious:

I run the 1st %LET statement, scroll down, run the program.

I run the 2nd %LET statement, scroll down, run the program.

 

I wrote a (much) simpler version of what I'm doing with sashelp.cars (attached)

Here's the primary thing:

I DO NOT want a macro around the PROC PRINT statement. I know how to do that.

I just want to know if there's a way to end each section of %LET statements with 'something' that calls the PROC PRINT program.

 

Thank you so much!

 

9.4M6 Windows

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

Why did you attach a file to post 20 lines of code?

%LET FILE=FILE1;
%LET VAR=MODEL;
%LET COND=Type='Sedan';
*Can I add a line of code here to run lines 18-22;

%LET FILE=FILE2;
%LET VAR=MODEL;
%LET COND=Type='SUV';
*Can I add a line of code here to run lines 18-22;

%LET FILE=FILE3;
%LET VAR=MODEL;
%LET COND=Type='Wagon';
*Can I add a line of code here to run lines 18-22;

%LET FILE=FILE4;
%LET VAR=MODEL;
%LET COND=Type='Truck';*Can I add a line of code here to run lines 18-22;

ODS RTF file="C:/temp/&&FILE..rtf";
options nodate pageno=1 linesize=80 pagesize=30 obs=10;
PROC PRINT DATA=SASHELP.CARS NOOBS LABEL;
  VAR &VAR;
  WHERE &COND;
RUN;
ODS RTF CLOSE;

So if you want to re-run a constant block of text you can either type it again or use your editor to insert it. Most editors including the editors in the various SAS user interfaces have that feature.  You could have the block of code in another editor window and run it from there.  You could have the block of code in a file on the SAS server and use a %INCLUDE statement to run it.

%include "mycode.sas";

You could put the code into a macro variable and then just expand the macro variable to run it.

data _null_;
  call symputx('code','ODS RTF file="C:/temp/&FILE..rtf";
options nodate pageno=1 linesize=80 pagesize=30 obs=10;
PROC PRINT DATA=SASHELP.CARS NOOBS LABEL;
  VAR &VAR;
  WHERE &COND;
RUN;
ODS RTF CLOSE;');
run;
...
&code.

You could define a macro that takes no parameters and just uses the existing macro variables. 

%macro code;
ODS RTF file="C:/temp/&FILE..rtf";
options nodate pageno=1 linesize=80 pagesize=30 obs=10;
PROC PRINT DATA=SASHELP.CARS NOOBS LABEL;
  VAR &VAR;
  WHERE &COND;
RUN;
ODS RTF CLOSE;
%mend;
...
%code

You could define a macro that does have parameters, but uses the existing macro variables when no values are passed in the parameters.

%macro code(outfile,varlist,wherecond);
%if 0=%length(&outfile) %then %let outfile=&file;
%if 0=%length(&varlist) %then %let varlist=&var;
%if 0=%length(&wherecond) %then %let wherecond=&cond;
ODS RTF file="C:/temp/&OUTFILE..rtf";
options nodate pageno=1 linesize=80 pagesize=30 obs=10;
PROC PRINT DATA=SASHELP.CARS NOOBS LABEL;
  VAR &VARLIST;
  WHERE &WHERCOND;
RUN;
ODS RTF CLOSE;
%mend;
...
%code()

Also you could put the values into a dataset instead of typing so many %LET statements and use CALL EXECUTE() to generate the code to run.

data _null_;
  set list;
  call execute(catx(' '
,'ODS RTF file=' ,quote(cats('C:/temp/',file,'.rtf')
,';options nodate pageno=1 linesize=80 pagesize=30 obs=10;'
,'PROC PRINT DATA=SASHELP.CARS NOOBS LABEL;'
,'VAR',var,';'
,'WHERE',cond,';'
,'RUN;'
,'ODS RTF CLOSE;'
));
run;

View solution in original post

11 REPLIES 11
Tom
Super User Tom
Super User

Why did you attach a file to post 20 lines of code?

%LET FILE=FILE1;
%LET VAR=MODEL;
%LET COND=Type='Sedan';
*Can I add a line of code here to run lines 18-22;

%LET FILE=FILE2;
%LET VAR=MODEL;
%LET COND=Type='SUV';
*Can I add a line of code here to run lines 18-22;

%LET FILE=FILE3;
%LET VAR=MODEL;
%LET COND=Type='Wagon';
*Can I add a line of code here to run lines 18-22;

%LET FILE=FILE4;
%LET VAR=MODEL;
%LET COND=Type='Truck';*Can I add a line of code here to run lines 18-22;

ODS RTF file="C:/temp/&&FILE..rtf";
options nodate pageno=1 linesize=80 pagesize=30 obs=10;
PROC PRINT DATA=SASHELP.CARS NOOBS LABEL;
  VAR &VAR;
  WHERE &COND;
RUN;
ODS RTF CLOSE;

So if you want to re-run a constant block of text you can either type it again or use your editor to insert it. Most editors including the editors in the various SAS user interfaces have that feature.  You could have the block of code in another editor window and run it from there.  You could have the block of code in a file on the SAS server and use a %INCLUDE statement to run it.

%include "mycode.sas";

You could put the code into a macro variable and then just expand the macro variable to run it.

data _null_;
  call symputx('code','ODS RTF file="C:/temp/&FILE..rtf";
options nodate pageno=1 linesize=80 pagesize=30 obs=10;
PROC PRINT DATA=SASHELP.CARS NOOBS LABEL;
  VAR &VAR;
  WHERE &COND;
RUN;
ODS RTF CLOSE;');
run;
...
&code.

You could define a macro that takes no parameters and just uses the existing macro variables. 

%macro code;
ODS RTF file="C:/temp/&FILE..rtf";
options nodate pageno=1 linesize=80 pagesize=30 obs=10;
PROC PRINT DATA=SASHELP.CARS NOOBS LABEL;
  VAR &VAR;
  WHERE &COND;
RUN;
ODS RTF CLOSE;
%mend;
...
%code

You could define a macro that does have parameters, but uses the existing macro variables when no values are passed in the parameters.

%macro code(outfile,varlist,wherecond);
%if 0=%length(&outfile) %then %let outfile=&file;
%if 0=%length(&varlist) %then %let varlist=&var;
%if 0=%length(&wherecond) %then %let wherecond=&cond;
ODS RTF file="C:/temp/&OUTFILE..rtf";
options nodate pageno=1 linesize=80 pagesize=30 obs=10;
PROC PRINT DATA=SASHELP.CARS NOOBS LABEL;
  VAR &VARLIST;
  WHERE &WHERCOND;
RUN;
ODS RTF CLOSE;
%mend;
...
%code()

Also you could put the values into a dataset instead of typing so many %LET statements and use CALL EXECUTE() to generate the code to run.

data _null_;
  set list;
  call execute(catx(' '
,'ODS RTF file=' ,quote(cats('C:/temp/',file,'.rtf')
,';options nodate pageno=1 linesize=80 pagesize=30 obs=10;'
,'PROC PRINT DATA=SASHELP.CARS NOOBS LABEL;'
,'VAR',var,';'
,'WHERE',cond,';'
,'RUN;'
,'ODS RTF CLOSE;'
));
run;
MelissaM
Obsidian | Level 7
Is there a way to use the %INCLUDE statement and call the lines of code within the same SAS session? Just curious.
Tom
Super User Tom
Super User

@MelissaM wrote:
Is there a way to use the %INCLUDE statement and call the lines of code within the same SAS session? Just curious.

 

If you are using Display Manager or SAS/Studio you can just highlight the lines of code with your mouse of cursor keys and submit them.

 

If you want to run SAS interactively without Display Manager. So that you have to type each line at the terminal. Then there is a feature to recall and re-run specific lines from earlier in your session. But then you don't have any of the nice features of interactive SAS.

 

Shmuel
Garnet | Level 18

As you "DO NOT want a macro around the PROC PRINT statement." 

may be you'll prefer next method: ( tested code without ODS )

data _null_;
   input file $ var $ type $;
   call execute("options nodate pageno=1linesize=80 pagesize=30 obs=10;");
   call execute('ODS RTF file="C:/temp/' || strip(file) || '.rtf";');
   call execute("PROC PRINT DATA=SASHELP.CARS NOOBS LABEL;");
   call execute("var " || strip(var) || ";");
   call execute("where type='" || strip(type) || "';  RUN; ODS RTF CLOSE");
cards;
file1  model  Sedan
file2  model  SUV
file3  model  Wagon
file4  model  Truck;
run cancel; 

 

   

PaigeMiller
Diamond | Level 26

I DO NOT want a macro around the PROC PRINT statement. I know how to do that.

 

A macro, of course, is one tool in SAS that allows you to use specific blocks of code repeatedly, and via the use of macro parameters, change certain pieces of text in that block of code. You make your own life more difficult by excluding a method that SAS specifically created for the purpose.


So, yes of course, the other methods, such as %include, CALL EXECUTE and CALL SYMPUTX all work, but I don't see what you gain in this situation (and in my opinion, they are harder to code or have other drawbacks).

--
Paige Miller
DonH
Lapis Lazuli | Level 10

Not sure why you don't want to use a macro. Regardless, you could consider using the dosubl routine instead of call execute.

Call execute stacks the statements you pass to it so they run after the data step. The dosubl routine calls them immediately. That allows you to not worry about concatenating the data step variables (as suggested in this very nice alternative) and dealing with where quotes go when constructing the code string. Just use macro variable references instead - and single quotes for the code string, thus preventing resolution during compile of the data step.

The array _char is used to load the values of the current row into macro vars.

 

data _null_;
   input file $ var $ type $;
   array _char(*) _character_;
   do i = 1 to dim(_char);
      call symputx(vname(_char(i)),_char(i));
   end;
   codeline = 'options nodate pageno=1 linesize=80 pagesize=30 obs=10;'
            ||'ODS RTF file="C:/temp/&file..rtf";'
            ||'PROC PRINT DATA=SASHELP.CARS NOOBS LABEL;'
            ||'var &var;'
            ||'where type="&type"; RUN; ODS RTF CLOSE;'
   ; 
   rc = dosubl(codeline); 
cards;
file1  model  Sedan
file2  model  SUV
file3  model  Wagon
file4  model  Truck
run; 
DonH
Lapis Lazuli | Level 10

And if the code you want to use is relatively static you can save it in a file (including the macro variable references) and use the dosub routine instead. The difference between them is:

  • dosubl expects as its argument a single character string which is the lines of code you want to execute.
  • dosub expects as its argument a character string whose value is the fileref that points to the code to be executed.

Here is that code:

filename code 'C:\temp\LetStmtAlternative.sas';
data _null_;
   input file $ var $ type $;
   array _char(*) _character_;
   do i = 1 to dim(_char);
      call symputx(vname(_char(i)),_char(i));
   end;
   rc = dosub('code'); 
cards;
file1  model  Sedan
file2  model  SUV
file3  model  Wagon
file4  model  Truck
run; 

And here is the contents of the file pointed to by the filename statement:

options nodate pageno=1 linesize=80 pagesize=30 obs=10;
ODS RTF file="C:/temp/&file..rtf";
PROC PRINT DATA=SASHELP.CARS NOOBS LABEL;
var &var;
where type="&type";
RUN;
ODS RTF CLOSE;

The advantage here is there is absolutely no quoting issue - you are running the code just like it is %included - but you don't have to generate the %include statement to be passed along for execution.

Tom
Super User Tom
Super User

Your code works fine with CALL EXECUTE also. The macro variables set by the CALL SYMPUT will be resolved when the CALL EXECUTE runs.  Just make sure to use single quotes in around the text passed to CALL EXECUTE(), just like you did for DOSUBL().

Shmuel
Garnet | Level 18

I have tested the code replacing line

rc = dosubl(codeline);

with

call execute(codeline);

ant it worked fine too.

DonH
Lapis Lazuli | Level 10

Interesting.

I wonder when that changed. I know that, as this blog post says, https://blogs.sas.com/content/sgf/2017/08/02/call-execute-for-sas-data-driven-programming/, that call execute had a timing issue and always used the values set for the macro variables on the last execution of the data step.
Looks like SAS enhanced call execute to resolve the values at execution time (something like an implied call to the RESOLVE function).

Tom
Super User Tom
Super User

The timing issue with call execute() and macros occurs when calling a macro that has logic that depends on macro variables that are generated/modified by the SAS code that the macro generates.  If you don't delay the macro call until after the data step execution has finished then the macro logic runs during the CALL EXECUTE() operation and makes it decisions about what code to generate before the generated SAS code has a chance to run and set/change the macro variables.

 

That does not apply in this case.

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
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
  • 11 replies
  • 1418 views
  • 1 like
  • 5 in conversation