BookmarkSubscribeRSS Feed
kansas
Calcite | Level 5

Hi,

After researching i found out two methods of looping a macro based on a dataset variable.

suppose my

dataset = data1 and variable=var1

Purpose: I need to run "my_macro" for each var1 value in the dataset

method1

%macro my_macro(var);

<macro statements>

%mend;

data _null_;

set data1;

call execute("%my_macro(" || var1 || ");");

run;

method2

Can use macro arrays introduced in http://www2.sas.com/proceedings/sugi31/040-31.pdf (Tight looping with macro arrays)

Both methods work perfectly.. But i want to know the most recommended method. (By number of lines, method1 seems the best for me. )

Thanks in advance.

11 REPLIES 11
art297
Opal | Level 21

Do you need to run the macro for each record or just for each unique value in var1?

kansas
Calcite | Level 5

above is an example art297. My aim is to change the parameter value in a macro based on a dataset vallues.

yes for each record

sbb
Lapis Lazuli | Level 10 sbb
Lapis Lazuli | Level 10

Note from the SAS documentation, your CALL EXECUTE will not be executed until the DATA step has been completed (up to the RUN; statement).  And so the macro code cannot be a continuation of the current DATA step.  Given this situation, it will be important to know what SAS statements are contained in your SAS macro for execution.

Also you will see the SAS execution logic with this additional diagnostic statement, at least prior to your DATA step:

OPTIONS SOURCE SOURCE2 MACROGEN SYMBOLGEN /* MLOGIC */ MPRINT;

Scott Barry

SBBWorks, Inc.

Suggested Google advanced search argument, this topic / post:

call execute site:sas.com

kansas
Calcite | Level 5

ok. this is what i'm trying to achieve
suppose a dataset containining var1
values
22

36

25

i want to run my macro for each and every value of var1 (var1 values are unique).

so basically,this is what im going to achieve by using a call execute step.

%my_macro(22);

%my_macro(36);

%my_macro(25);

and how does "SAS statements are contained in your SAS macro for execution" going to affect the program ?

my macro has some proc statements and some datasteps.

The code works as expected. I want know whether this code is against the coding best practices.

Thanks.

art297
Opal | Level 21

Can you post an actual example, including sample data along with your macro and code that calls it?

mojerry2
Fluorite | Level 6

there are multiple solutions to have the same result.

I think your method is the best one even if the call execute will be executed at the end of your datastep. so first reading the whole dataset and then execute your macro calls.

the other method is like a nice "brainfuck" but can be really useful.

but if you want to use this option then you have to put all your variables in an array and then use the %do_over

kansas
Calcite | Level 5

"so first reading the whole dataset and then execute your macro calls."
so macro statement wont be executed until the datastep completely finishes ? All this time i was thinking that macro statement gets executed at the end of each iteration .

data_null__
Jade | Level 19

Most of the time when a macro is called with CALL EXECUTE and the macro generates SAS datastep and proc code you want to delay execution of the macro until after the data step is finished.

Therefore you would change your code to include %NRSTR.

call execute("%my_macro(" || var1 || ");");

to

call execute("%nrstr(%my_macro(" || var1 || ");)");

Using NRSTR will prevent the macro from being called when CALL EXECUTE "executes".  This is usually the action you need, especially if the macro being called uses data or proc steps to create or alter macro variables that are then used in subsequent program steps.

I think it is all explained in detail in the documentation which I encourage you to read.

DLing
Obsidian | Level 7

Here's a method to loop a macro over every value in a dataset.  The macro itself sequentially reads a SAS dataset, so it doesn't use a macro array, and since it's done in a macro, there's no call execute.  All the methods above should work, this is another one of many approaches possible.

%macro loop( data );

    %let dsid=%sysfunc(open(&data));

    %if (&dsid = 0) %then %do;   

        %put %sysfunc(sysmsg());

        %return;

    %end;

    %syscall set(dsid);          * links sas dataset variables to macro variables, watch out for name collision ;

    %do %while( %sysfunc(fetch(&dsid)) = 0 );

        %work(&msgid)               * replace with anything you need like a macro call with arguments ;

    %end;

    %let dsid=%sysfunc(close(&dsid));

%mend;

%macro work( arg );

     %put &arg;

%mend;

%loop( sashelp.adomsg )

This version lists the "msgid" column from sashelp.adomsg dataset.

It illustrates the idea of using a macro to loop over SAS dataset and generate code.  And because it's all inside a macro, the looping and code generation is easier without needing to maintain arrays... etc.

Modify to suite your needs Smiley Happy

kansas
Calcite | Level 5

Thanks Dling. Will definitely try your code as well

Peter_C
Rhodochrosite | Level 12

As a list of calling parameters is not always sourced from a data set, you might like a look at this alternative.

Not limited to execution within a data step, there is a macro looper described in a SUGI paper http://www2.sas.com/proceedings/sugi31/012-31.pdf

peterC

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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
  • 11 replies
  • 1716 views
  • 0 likes
  • 7 in conversation