How to loop sas macro by date? - loops

I defined a macro which get data of 1 day.
For example
%macro getOneday(stnd_d);
data _null_;
call symputx('numdate',&stnd_d.);
run;
data oneday&numdate;
set alldata;
where stdd = &stnd_d;
run;
%mend;
Now I want to loop that macro from start date to end date.
data _null_;
do i = '01mar2015'd to '30mar2015'd;
%getOneday(stnd_d = i)
end;
run;
I don't know how can I pass the date expression value to %getOneday() as a parameter.

I hope you understand that macro - getOneday would simply write all the code written inside it, to the data _null_ statement by replacing the %getOneday and since you cannot write a data step inside a data step, its throwing an error. You simply have to replace the data _NULL_ statement with a macro like below.
Also using date like that would not work as Macro would treat them as char, you will have to convert them into date format, before using them in %do loop.
%macro test;
data _null_;
date1='01mar2015'd;
date2='30mar2015'd;
call symputx("date1",date1);
call symputx("date2",date2);
run;
%put &date1.;
%put &date2.;
%do i = &date1. %to &date2.;
%getOneday(stnd_d = &i.)
%end;
%mend;
%test;

Related

sas macro variable in loop thru end of month

my idea is to get a data set from tables where the variable is dynamically created based on the end of the month date. I know I'm missing sth with format/informat of a variable, but I'm super lost, please help me understood what I'm missing:
I need variable YYYYMMDD to look like ie20200229 to be sure to get leap year right.
I have database with no partion that's why each end of month is in different table.
%MACRO MEH;
%DO n=2018 %TO 2022;
&LET yyyy = n;
%DO i=1 %TO 12;
%LET mm= i;
%LET YYYYMMDD= %sysfunc(putn(intnx(month,mdy(( input(&mm.),28,input(&yyyy.)),0,e), YYMMDDN8.)); /*IE. 20200229 */
RUN;
/*this part works*/
PROC SORT DATA=XYZ.NAME_OF_TABLE_&YYYYMMDD.
out=work.NEW_NAME&YYYYMMDD. nodupkey;
by SOME_ID;
RUN;
/* MORE CODE HERE*/
DATA work.TEMP2;
MERGE work.TEMP1
work.NEW_NAME&YYYYMMDD;
BY SOME_ID;
RUN;
DATA work.WIN&YYYYMMDD.;
MERGE work.TEMP6
work.TEMP2;
BY SOME_ID;
RUN;
/* MORE CODE Here this code do sorting merging and filtering specific vales i did on SQL but I'm missing some function (like lag, to do in on SQL only) */
/*END OF WORKING CODE*/
/*CEAN UP*/
proc datasets nolist lib=work;
DELETE NEW_NAME: ;
DELETE TEMP: ;
RUN;
%END;
%END;
%MEND MEH;
%MEH;
To loop over date intervals it is usually easier to use an integer index. You can then use INTNX() function to to calculate the next interval's start date. You can use INTCK() to calculate how many iterations are required.
%let start='01JAN2018'd;
%let end='01DEC2012'd;
%do offset=0 %to %sysfunc(intck(month,&start,&end));
%let ymd = %sysfunc(intnx(month,&start,&offset),yymmddn8.);
....
%end;
Drop the YYYY and mm macro variables as they're redundant
Remove the RUN as well, not required
Then you can replace the top of your macro with the following:
%DO n=2018 %TO 2022;
%DO i=1 %TO 12;
%LET YYYYMMDD= %sysfunc(intnx(month, %sysfunc(inputn(&n.&i., yymmn6.)), 0, e), yymmddn8.); /*IE. 20200229 */
%put &yyyymmdd.; * for testing;

Loop and join table

Let say I want to loop for i = 2002 to 2006 and in each loop, I create a key word like:
w2006
w2005
w2004
w2003
w2002
And each keyword will be the input for a macro, let say mymacro(keyword) which create a table named "result&key" (for example: resultw2006), so that I want to execute 5 time : %mymacro(w2006), %mymacro(w2005)... %mymacro(w2002) to have 5 tables and join them after that.
Do you have any idea of how to do this? In fact I tried but it doesn't work, here is my code:
%macro tojoin;
%do i=2002 %to 2006;
key=w&i;
%mymacro(&key);
%data result;
set result result&key;
%run;
output;
%end;
%mend;
You need to provide more information on what SAS code you are tying to use the macro processor to generate to get a real answer.
But assuming that %MYMACRO will generate a dataset named result&key then it looks like you want to run something like this to call it 5 times and append the results into a single dataset.
%macro tojoin;
%local key;
%do i=2002 %to 2006;
%let key=w&i;
%mymacro(&key);
proc append base=result data=result&key;
run;
%end;
%mend;
You don't need % in front of data or run, you need a %let statement, and you don't need the output command. So:
%macro tojoin;
%do i=2002 %to 2006;
%let key=w&i;
%mymacro(&key);
data result;
set result result&key;
run;
%end;
%mend;
Tom's method is cleaner, but your code was basically correct - just a bit of cleanup needed.

SAS Macro Do Loop Issues

I have a very simple request. Loop through a dataset, turning each observation into a macro variable, and then doing a comparison on that macro variable. here's what my code looks like:
%do n = 1 %to &i2.;
data want;
set have;
%if _N_ = &n. %then %do;
call symputx("Var1",var1);
call symputx("var2",var2);
%end;
run;
data want;
retain FinalCount
set have;
where Variable1="&var1.";
by SomeVariable
if first.SomeVariable then FinalCount=0;
if final="FINAL" then FinalCount+1;
if Finalcount=&var2. then Final_Samples=1;
finalCount=FinalCount;
run;
%end
The part that is failing in the _N_ = &n. section. I keep getting the error "Variable N has been defined as both character and numeric." Basically I just need to set each observation as a macro variable once to do the next comparison, and then move on to the next guy. So, if there's a better way of doing that, please let me know. Otherwise, could you help me figure out why that comparison is not working?
If you could explain your larger problem then you might get a better answer that does not require you to convert your data values into macro variables. Converting values to strings and then trying to compare them again introduces a number of sources of errors.
To your question of how to set macro variables based on the Nth observation in a dataset, try one of these.
If it supports the FIRSTOBS= and OBS= dataset options.
data _null_;
set have (firstobs=&n obs=&n);
call symputx("Var1",var1);
call symputx("var2",var2);
run;
If the dataset supports direct access then use that.
data _null_;
p = &n;
set have point=p;
call symputx("Var1",var1);
call symputx("var2",var2);
stop;
run;
If not then use an IF (not a macro %if).
data _null_;
set have ;
if _n_ = &n then do;
call symputx("Var1",var1);
call symputx("var2",var2);
stop;
end;
run;

Sas loop for start date and end date

I have a code here, where I take a start date and end date from the user and execute a macro for those 2 dates.
%let mon_last=31MAR2019;
%let mon_first=01JAN2019;
%macro call();
data _null_;
array datelist {2} "&mon_first"d "&mon_last"d;
%do i=1 %to 2;
%let yrmon1=%sysfunc(inputn(datelist{i},mmddyy10.), date9.));
%let yrmon=%sysfunc(putn(&yrmon1,date9.),yymmn6.);
%let yr=%sysfunc(year(&yrmon1),4);
%let mon=%sysfunc(month(&yrmon1),z2);
%datapull(&yrmon., &yr., &mon.);
%end;
%mend;
%call();
But I end up getting the following error whichever way I try:
WARNING: Argument 1 to function INPUTN referenced by the %SYSFUNC or %QSYSFUNC macro function is out of range.
NOTE: Mathematical operations could not be performed during %SYSFUNC function execution. The result of the operations have been set
to a missing value.
ERROR: The function PUTN referenced by the %SYSFUNC or %QSYSFUNC macro function has too few arguments.
The macro processor considers everything as a string. You cannot convert the string datelist{i} into a date value.
Looks like you want to have a macro that can take as input a list of strings that are in a format that can be converted into date values and use those to call another macro.
%macro call(date_list);
%local i yrmon yr mon;
%do i=1 %to %sysfunc(countw(&date_list));
%let yrmon=%sysfunc(inputn(%scan(&date_list,&i),date11.),yymmn6.);
%let yr=%substr(&yrmon,1,4);
%let mon=%substr(&yrmon,5);
%datapull(&yrmon., &yr., &mon.);
%end;
%mend;
%call(31MAR2019 01JAN2019);
If instead you wanted to process every month from start to end then you want a different macro with different inputs. In that case you just need two inputs that each can only have one value.
This time let's code it so that the burden of supplying valid date values falls onto the caller of the macro instead of accepting character strings that need to be converted into dates.
%macro call(start,end);
%local i yrmon yr mon;
%do i=0 %to %sysfunc(intck(month,&start,&end));
%let yrmon=%sysfunc(intnx(month,&start,&i),yymmn6.);
%let yr=%substr(&yrmon,1,4);
%let mon=%substr(&yrmon,5);
%datapull(&yrmon., &yr., &mon.);
%end;
%mend;
%call("01JAN2019"d,"31MAR2019"d);

Insert a variable number of rows

Currently, my macro is running to insert a constant number of rows:
%MACRO ADD_PERIOD;
%DO P = 1 %TO 39;
Would I be able to modify this macro or create a new macro to run this, not 39 times, but replace the number of loops with a variable I have from another table?
Thank you!
Use the call symput to turn that variable(my_var) into a macro variable(loop_var)
data _null_;
set your_table;
call symput("loop_var", my_var);
run;
and use & to resolve the macro variable into your code
%MACRO ADD_PERIOD;
%DO P = 1 %TO &loop_var;
You could also pass that macro variable as parameters into your macro.
%MACRO ADD_PERIOD(loop_var);

Resources