Hi all!
I am reading some codes and wondering if anyone familiar with MACRO can help me out:
/* Run Parameters : */
/* Below parameters need to change before running report in Feb */
/*******************************************************************/
%LET RUNYEAR=%SYSFUNC(YEAR(%EVAL(%SYSFUNC(TODAY())-10)));
%LET NextYEAR=%EVAL(&RUNYEAR.+1);
%LET PREVYEAR=%EVAL(&RUNYEAR.-1);
%LET PREV2YEAR=%EVAL(&RUNYEAR.-2);
%LET RunYearDT = 2020-01-01 00:00:00;
%LET RunYearD = 01JAN2020;
%LET ContributionStartDT = '01/01/2014' and '12/31/2020';
%PUT RUNYEAR = &RUNYEAR. NextYEAR = &NextYEAR. PREVYEAR = &PREVYEAR. PREV2YEAR = &PREV2YEAR. RunYearDT = &RunYearDT. ContributionStartDT = &ContributionStartDT.;
Here my question is, why would we need to write eg:%LET RunYearDT = 2020-01-01 00:00:00; since we already have "%LET RUNYEAR=%SYSFUNC(YEAR(%EVAL(%SYSFUNC(TODAY())-10)));" in the first row? I thought this already helped us define the run year.
And since we run January data in Feb, I should change all the "2020" to "2021" I think? But same question came out, isn't runyear defined by the first macro step?
Thanks!
Macro variables just hold text. You need to understand what the text means and how to use that text to generate other code to run. First let's just run your %LET statements and see what text is being assigned to the macro variables.
Note the newish feature of the %PUT statement where when you type &=macrovar instead of ¯ovar it displays the name and the value.
156 %LET RUNYEAR=%SYSFUNC(YEAR(%EVAL(%SYSFUNC(TODAY())-10))); 157 %put &=runyear; RUNYEAR=2021 158 159 %LET NextYEAR=%EVAL(&RUNYEAR.+1); 160 %put &=nextyear; NEXTYEAR=2022 161 162 %LET PREVYEAR=%EVAL(&RUNYEAR.-1); 163 %put &=prevyear; PREVYEAR=2020 164 165 %LET PREV2YEAR=%EVAL(&RUNYEAR.-2); 166 %put &=prev2year; PREV2YEAR=2019 167 168 169 %LET RunYearDT = 2020-01-01 00:00:00; 170 %put &=runyeardt ; RUNYEARDT=2020-01-01 00:00:00 171 172 %LET RunYearD = 01JAN2020; 173 %put &=runyeard ; RUNYEARD=01JAN2020 174 175 176 %LET ContributionStartDT = '01/01/2014' and '12/31/2020'; 177 %put &=ContributionStartDT ; CONTRIBUTIONSTARTDT='01/01/2014' and '12/31/2020'
So the first one is the most complex. First let's simplify it a little.
%LET RUNYEAR=%SYSFUNC(YEAR(%SYSFUNC(TODAY())-10));
The %SYSFUNC() macro function let's you call regular SAS functions in macro code (almost all SAS functions can be called this way). In this case YEAR() and TODAY() are the functions being called, notice how each one needs its own %SYSFUNC() wrapper. The YEAR() function returns the year from a SAS date value. The TODAY() function returns the date value from the computers clock. SAS stores dates as number of days so subtracting 10 is moving 10 days into the past. Notice that when calling a SAS function in macro code via %SYSFUNC() you do not need to call %EVAL() for arithmetic you want to do on numeric arguments. The %SYSFUNC() interface to the SAS functions will make sure those expressions are evaluated.
Then you have two %LET statements that using %EVAL() macro function to perform some simple integer arithmetic. So in this one:
%LET NextYEAR=%EVAL(&RUNYEAR.+1);
You are passing into the %EVAL() function the string 2021+1 which it will see as a request to add the two numbers represented by the character strings on either site of the plus sign. The resulting number will be an integer that is then converted into a digit string that represents that number. In this case the string 2022.
Near the end you are making two macro variables with DT and D suffixed to their name. The strings being assigned look like the way that the DATETIME and DATE formats would display datetime and date values. But more importantly those strings are strings that the DATETIME and DATE informats will recognize as dateime and date values. So you could use those strings to create DATETIME or DATE literals by adding quotes and the proper suffix. For example you might use both of those macro variables in SAS code like this to compare some datetime or date variables to those constant values.
where run_datetime > "&RunYearDT"dt or run_date > "&RunYearD"d ;
The last example is stranger as you are assigning a multiple word string to the macro variable. It is probably not very useful for generating SAS code. You might use it to generate a title or a footnote. So code like:
title1 "Report for Contributions between &ContributionStartDT";
Would result in this actual TITLE statement:
title1 "Report for Contributions between '01/01/2014' and '12/31/2020'";
Or it might be useful in some code passed to a remote database where date constants can be expressed in that way. So perhaps something like:
proc sql ;
connect to oracle ..... ;
create table want as select * from connection to oracle
(select * from contributions where datevar between &ContributionStartDT)
;
So that the query sent to the ORACLE database is:
select * from contributions where datevar between '01/01/2014' and '12/31/2020'
But perhaps want you really want to do is use the PREVYEAR and NEXTYEAR macro variables to generate date literals that you could use in SAS code instead? So something like this in your program:
where datevar between "01JAN&prevyear"d and "31DEC&nextyear"d
Would result in this SAS code being run:
where datevar between "01JAN2020"d and "31DEC2022"d
You are using the year function in runyear so that just gets the year so if today is 1/27/2021, the year function would return 2021. Runyeardt is a whole date variable, not just the year.
You can figure out many of these questions by simply looking at the values of the macro variables.
%LET RUNYEAR=%SYSFUNC(YEAR(%EVAL(%SYSFUNC(TODAY())-10)));
%put &=runyear;
So your can see in the LOG that &RUNYEAR has a value of 2021.
Why do you need &RUNYEARDT? This is a text string containing a datetime value. At some point, you may need to work with datetime values, so &RUNYEAR doesn't get it done.
Whether or not you need to change the 2020 in the data to 2021 is up to you, we don't know what the rest of the code is doing.
Also, to clear up the terminology, your title implies you have a SAS macro question, but you do not. You have a question about macro variables. Macro variables are not macros, and macros are not macro variables, so it will be helpful to you (and helpful to us) not to confuse the two.
Macros are basically like text substitution. That statement is making a new macro variable called RunYearDt and assigning it to 2021-01-01 00:00:00. You can reference macro variables in other parts of the program by preceding them with &.
https://support.sas.com/resources/papers/proceedings/proceedings/sugi26/p153-26.pdf
Here's a paper where you can read more. SAS e-learning also has 2 courses SAS Macro 1 and SAS Macro 2 that you could study them. They are a powerful tool for automating repetitive tasks.
Did you try running the code and looking at the log?
260 /* Run Parameters : */
261 /* Below parameters need to change before running report in Feb */
262 /*******************************************************************/
263
264 %LET RUNYEAR=%SYSFUNC(YEAR(%EVAL(%SYSFUNC(TODAY())-10)));
265 %LET NextYEAR=%EVAL(&RUNYEAR.+1);
266 %LET PREVYEAR=%EVAL(&RUNYEAR.-1);
267 %LET PREV2YEAR=%EVAL(&RUNYEAR.-2);
268
269 %LET RunYearDT = 2020-01-01 00:00:00;
270 %LET RunYearD = 01JAN2020;
271 %LET ContributionStartDT = '01/01/2014' and '12/31/2020';
272 %PUT RUNYEAR = &RUNYEAR. NextYEAR = &NextYEAR. PREVYEAR = &PREVYEAR. PREV2YEAR = &PREV2YEAR. RunYearDT = &RunYearDT.272! ContributionStartDT = &ContributionStartDT.;
RUNYEAR = 2021 NextYEAR = 2022 PREVYEAR = 2020 PREV2YEAR = 2019 RunYearDT = 2020-01-01 00:00:00 ContributionStartDT = '01/01/2014'
and '12/31/2020'
This is what's in the log. I am assuming the DT means datetime. So that is in datetime format. Are you running some kind of routine report?
@yichentian226 wrote:
if we say "%LET RunYearDT = 2021-01-01 00:00:00", are we formating runyeardt?
No, you are create a macro variable RunYearDT that contains a value which is a text string 2021-01-01 00:00:00. There has been no formatting.
I am trying to learn what will this piece of code help us achieve/ what it does. I was thinking we should change the 2021 because we will only looking at 2021/01's numbers... just my thought haha
The best way to learn what the code is doing is to run it, and include debugging as I mentioned earlier, printing out values of the macro variables using the %PUT statement.
Macro variables just hold text. You need to understand what the text means and how to use that text to generate other code to run. First let's just run your %LET statements and see what text is being assigned to the macro variables.
Note the newish feature of the %PUT statement where when you type &=macrovar instead of ¯ovar it displays the name and the value.
156 %LET RUNYEAR=%SYSFUNC(YEAR(%EVAL(%SYSFUNC(TODAY())-10))); 157 %put &=runyear; RUNYEAR=2021 158 159 %LET NextYEAR=%EVAL(&RUNYEAR.+1); 160 %put &=nextyear; NEXTYEAR=2022 161 162 %LET PREVYEAR=%EVAL(&RUNYEAR.-1); 163 %put &=prevyear; PREVYEAR=2020 164 165 %LET PREV2YEAR=%EVAL(&RUNYEAR.-2); 166 %put &=prev2year; PREV2YEAR=2019 167 168 169 %LET RunYearDT = 2020-01-01 00:00:00; 170 %put &=runyeardt ; RUNYEARDT=2020-01-01 00:00:00 171 172 %LET RunYearD = 01JAN2020; 173 %put &=runyeard ; RUNYEARD=01JAN2020 174 175 176 %LET ContributionStartDT = '01/01/2014' and '12/31/2020'; 177 %put &=ContributionStartDT ; CONTRIBUTIONSTARTDT='01/01/2014' and '12/31/2020'
So the first one is the most complex. First let's simplify it a little.
%LET RUNYEAR=%SYSFUNC(YEAR(%SYSFUNC(TODAY())-10));
The %SYSFUNC() macro function let's you call regular SAS functions in macro code (almost all SAS functions can be called this way). In this case YEAR() and TODAY() are the functions being called, notice how each one needs its own %SYSFUNC() wrapper. The YEAR() function returns the year from a SAS date value. The TODAY() function returns the date value from the computers clock. SAS stores dates as number of days so subtracting 10 is moving 10 days into the past. Notice that when calling a SAS function in macro code via %SYSFUNC() you do not need to call %EVAL() for arithmetic you want to do on numeric arguments. The %SYSFUNC() interface to the SAS functions will make sure those expressions are evaluated.
Then you have two %LET statements that using %EVAL() macro function to perform some simple integer arithmetic. So in this one:
%LET NextYEAR=%EVAL(&RUNYEAR.+1);
You are passing into the %EVAL() function the string 2021+1 which it will see as a request to add the two numbers represented by the character strings on either site of the plus sign. The resulting number will be an integer that is then converted into a digit string that represents that number. In this case the string 2022.
Near the end you are making two macro variables with DT and D suffixed to their name. The strings being assigned look like the way that the DATETIME and DATE formats would display datetime and date values. But more importantly those strings are strings that the DATETIME and DATE informats will recognize as dateime and date values. So you could use those strings to create DATETIME or DATE literals by adding quotes and the proper suffix. For example you might use both of those macro variables in SAS code like this to compare some datetime or date variables to those constant values.
where run_datetime > "&RunYearDT"dt or run_date > "&RunYearD"d ;
The last example is stranger as you are assigning a multiple word string to the macro variable. It is probably not very useful for generating SAS code. You might use it to generate a title or a footnote. So code like:
title1 "Report for Contributions between &ContributionStartDT";
Would result in this actual TITLE statement:
title1 "Report for Contributions between '01/01/2014' and '12/31/2020'";
Or it might be useful in some code passed to a remote database where date constants can be expressed in that way. So perhaps something like:
proc sql ;
connect to oracle ..... ;
create table want as select * from connection to oracle
(select * from contributions where datevar between &ContributionStartDT)
;
So that the query sent to the ORACLE database is:
select * from contributions where datevar between '01/01/2014' and '12/31/2020'
But perhaps want you really want to do is use the PREVYEAR and NEXTYEAR macro variables to generate date literals that you could use in SAS code instead? So something like this in your program:
where datevar between "01JAN&prevyear"d and "31DEC&nextyear"d
Would result in this SAS code being run:
where datevar between "01JAN2020"d and "31DEC2022"d
Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.
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.
Ready to level-up your skills? Choose your own adventure.