Build macro Variables on another macro var - sas

I would like to "shortcut" this function of a macro variable
intnx('YEAR',"&starting_year"D,-5,'S');
with another macro variable. Is it possible ?
something like:
%let start = intnx('YEAR',"&starting_year"D,-5,'S');
Of course this code-line doesn't work.

You can use %SYSFUNC() to call functions in macro code. You can use the optional format specification to control how the results is converted to the text that is stored in the macro variable.
So if you start with macro variable in DATE. format you could generate the date that was 5 years before that date like this:
%let start=%sysfunc(intnx(year,"&starting_date"d,-5,s),date9);
This would convert 20MAR1999 to 20MAR1994. Or it would convert 29FEB04 to 28FEB1999.

%sysfunc lets you call regular SAS functions in the macro language. Perhaps something like (untested) :
%let start = %sysfunc(intnx(YEAR,"&starting_year"D,-5,S));

Related

SAS MACRO how to assign MACRO to date9

I try to reassign macro to new macro, which I want to create date9.
so my code is this
%Let CALYEAR =2020;
%let AYEAR =%SYSEVALF(&CALYEAR-1);
FALLSTART_ONE=%sysfunc(15AUG&AYEAR,date9.);
so I assume Macro variable "AYEAR" is 2019 and I want to create macro variable "FALLSTART_ONE" =15AUG2019
but error is
212 FALLSTART_ONE=%sysfunc(15AUG&AYEAR,date9.);
-------------
180
ERROR: Function name missing in %SYSFUNC or %QSYSFUNC macro function reference.
How should I fix it?
Thanks
You need a %let. You also do not need to enclose it in %sysfunc(). You can build the string as-is.
%let FALLSTART_ONE=05AUG&AYEAR;

symputx won't let me store different macro variables with the same macro function

I'm trying to write a macro function that gets attributes from a data set, and then stores them as a macro variable. I want to write this macro function in such a way that it can be used for multiple data sets, and multiple macro variables.
What's wrong with this:
%macro ExtractACell(dataset, storage_var, rownum=1, var_name=Make);
data _null_;
set &dataset. (obs=&rownum. firstobs=&rownum. keep = &var_name.);
call symputx(&storage_var., &var_name., "G");
stop;
run;
%mend ExtractACell;
Whenever I try to run that I get notes like this:
NOTE: The quoted string currently being processed has become more than 262 bytes long. You might have unbalanced quotation marks.
NOTE: The quoted string currently being processed has become more than 262 bytes long. You might have unbalanced quotation marks.
27 %let SASWORKLOCATION="%sysfunc(getoption(work))/";
Does symputx have rules against passing in macro variables that represent names of macro variables?
Make sure you are generating valid SAS code when your macro variables are expanded. In particular this statement:
call symputx(&storage_var., &var_name., "G");
Would require you to call the macro with quotes around the name of the macro variable you want it to create. Like this:
%ExtractACell(dataset=sashelp.cars, storage_var="mymvar", rownum=1, var_name=Make);
It might be simpler to code the macro using this statement.
call symputx("&storage_var", &var_name., "G");
Then you could call without the quotes around the macro variable name:
%ExtractACell(dataset=sashelp.cars, storage_var=mymvar, rownum=1, var_name=Make);
PS Your whole process is probably messed up if you need that macro.

SAS does not evaluate the content of %PUT

I use this bit outside of any DATA step.
%let sth = 20191111;
%let sthelse=SUBSTR(INPUT(&sth.,12.),1,4);
%put &sthelse.;
It does not yield '2019', which I would expect but rather
SUBSTR(INPUT(20191111,12.),1,4)
What goes wrong here?
Use the macro function %SUBSTR to extract a portion of its argument. Remember, macro values are only character values (not to be confused with data step character variables and values) and have no explicit numeric value, even when the macro value is comprised of all digits.
%let sth = 20191111;
%let first4 = %substr(&sth,1,4);
You are not understanding how the macro pre-processor works. It is just a text replacement tool. It looks for two trigger character, % and & to see where it needs to do work. You can see both at work in your statement:
%let sthelse=SUBSTR(INPUT(&sth.,12.),1,4);
So the % will trigger the macro processor and it will recognize %let as a macro statement. Then the & trigger will cause it to treat &sth. as a macro variable reference to be replaced. So it replaces that and you end up with this statement.
%let sthelse=SUBSTR(INPUT(20191111,12.),1,4);
Since there are no more macro triggers SAS happily stores that text into the macro variable sthelse.
You also seem confused about how numbers and character strings work. If you write this code:
data x;
x=INPUT("20191111",12.);
run;
You would be asking SAS to convert the string 20191111 into the number 20,191,111. So X would be a numeric variable. So it would have the same effect as if you ran this statement instead.
x=20191111;
Now if you then ask SAS to try to use the SUBSTR() function on that NUMERIC value by doing this:
y=substr(x,1,4);
SAS will need to first convert X into a character string. It will happily do that for you, but it will use the BEST12. format to make the conversion. So your number 20,191,111 will become the string
20191111
So it will have 4 leading spaces. Then if you take the first four characters you end up with four spaces.
Did you intend to run this code instead?
%let sth = 20191111;
%let sthelse=%substr(&sth,1,4);
That will use the MACRO function %SUBSTR() to take the first four characters of the string you have given it. Since you gave it the string 20191111 (to the macro processor everything is a string, no quotes needed) the result will be the string 2019.
SUBSTR is datastep function.
Try to use it into macro function:
%let sth = 20191111;
%let sthelse=%sysfunc(SUBSTR(%sysfunc(INPUTn(&sth.,12.)),1,4));
%put &sthelse.;
There isn't macro function named substr and input, this function is "data step functions". You should use %sysfunc statement. And macro variables stores as text, so you shouldn't use input function on it.
%let sth = 20191111;
%let sthelse=%sysfunc(SUBSTR(&sth.,1,4));
%put &=sthelse.;
STHELSE=2019
UPDATE(thanks #Tom):
There is macro function %substr, so you can use %SUBSTR(&sth.,1,4) instead of %sysfunc(SUBSTR(&sth.,1,4)).

SAS macro write text file with char and num parameter

I am trying to write a macro that creates a text file using parameter value. I understand all SAS parameters are passed as text, so i need to convert the text to numeric. Using INPUT for this but still getting a syntax error. Appreciate the help. Thank you.
code:
%macro test(n_var);
data _null_;
file"c:/temp/test.txt" TERMSTR=crlf;
put ;
put "(numeric variable passed = "input(&n_var,8.)")";
put ;
run;
%mend;
%test(n_var=100);
Log:
SYMBOLGEN: Macro variable N_VAR resolves to 100
NOTE: Line generated by the macro variable "N_VAR".
39 100
___
22
76
MPRINT(TEST): put "(numeric variable passed = "input(100,8.)")";
MPRINT(TEST): put ;
MPRINT(TEST): run;
ERROR 22-322: Syntax error, expecting one of the following: a name, arrayname, _ALL_, _CHARACTER_, _CHAR_, _NUMERIC_.
ERROR 76-322: Syntax error, statement will be ignored.
All SAS macro symbols (aka variables) are text. SAS macro parameters are text.
Your use case probably does not need to convert text to numeric.
Consider:
%let x = 100;
data _null_;
my_num_var = &x;
run;
The resolution of the macro variable (or perhaps better understood as 'symbol') are the letters 1 0 0, but with respect to text to be interpreted as SAS code. The data step compiler infers my_num_var is numeric from the line it sees as
my_num_var = 100;
There are some use cases where you may want to test that a macro parameter can be interpreted as a numeric value. Such use cases are probably beyond your needs at this time.
The INPUT function is one of those special DATA Step functions that is not available for use in SAS macro via the %sysfunc function. When you must 'input' a value in a 'pure' manner outside a DATA step, you will want to invoke the INPUTN or INPUTC functions via %sysfunc
%let evaluatedRepresentation = %sysfunc(inputn(&x,best8.));
The numeric evaluation of the inputn is converted to text and assigned to symbol evaluatedRepresentation.
If you are not in control of the callers to you macros in which you do ampersand evaluations the safer approach is to evaluate via SUPERQ to break code injections and other anamolies
%let evaluatedRepresentation = %sysfunc(inputn(%superq(x),best8.));

Why proc does not need a % symbol when written inside a SAS macro

I have a basic question about SAS macro. Inside sas macro, when you write a let statement or a put statement or an if statement, you always prefix it with %.
But when you write a 'proc' inside a macro, why don't we need to write %proc?
Or for example %data?
Because the data step language and macro language are two different programming environments. When SAS tokenizes your statements, it looks for specific keywords. One of those keywords is the % trigger. Before anything is run, the word scanner separates out macro statements from SAS statements and passes them to the appropriate processor. Macro statements are always compiled and resolved before SAS statements.
When you are working with macros, you're storing text strings in either some macro variable or macro program. Anything inside of the macro variable or program is raw text as far as SAS is concerned.
Consider the following two macros:
Macro 1:
%macro foo1;
data bar1;
var1 = 'a';
var2 = 'b';
var3 = 'c';
var4 = 'd';
keep var1-var3;
run;
%mend;
Macro 2:
%macro foo2;
keep
%do i = 1 %to 3;
var&i
%end;
%mend;
data bar2;
var1 = 'a';
var2 = 'b';
var3 = 'c';
var4 = 'd';
%foo2;
run;
When you compile Macro 1, nothing happens until you call it. This is because you have stored all of that text inside of a macro program. When you call the macro statement:
%foo1;
SAS passes the phrase foo1 to the macro processor, the program is run, and the resolved text is spat back into the word scanner, which then processes the individual tokens one by one. As far as SAS is concerned, it sees exactly the datastep contained inside:
data bar1;
var1 = 'a';
var2 = 'b';
var3 = 'c';
var4 = 'd';
keep var1-var3;
run;
When we run Macro 2, we'll get the exact same output, but it's being performed differently.
When we compile the macro foo2, we also store some information about an internal macro loop. This particular loop simply creates the text "var1 var2 var3" sequentially. Notice that there's a piece of text right before the loop: "keep." This is completely valid since it's just a piece of text.
We execute the macro inside of the data step. When we start the compilation process of the data step, the word scanner finds the macro trigger % and passes that information along to the macro processor. When it finds that foo2 is a valid compiled macro, the macro processor runs the macro program, and the resulting text is sent over to the word scanner:
keep
var1
var2
var3
We end invocation of the macro with a semicolon on purpose. This tells the word scanner that we are at the end of a statement, which eventually gets sent over to the compiler.
Once the macro is complete, the word scanner keeps chugging along, passing statements to the input stack until it hits the run boundary, or another proc step.
We could invoke foo2 outside of a data step, but SAS will error out saying that they're not valid statements. It's equivalent to typing keep var1 var2 var3; on a line and trying to run it. That specific piece of text is only useful inside of a data step, though SAS will happily attempt to run it wherever you want.
SAS doesn't see macros. It only understands data step and proc language. Only the macro processor can see and make use of macro triggers. The word scanner prevents the compiler from seeing any of the macro triggers. Think of the word scanner like a special filter: it hands out text only to the places that can read it.
There are a few exceptions where some functions in the data step can bridge the gap between SAS and macros, but it doesn't really have anything to do with this.
% denotes macro syntax - macro functions, macro statements, or macro commands. Basically, things that would be covered by the SAS Macro Language Reference.
When you have a proc in a macro, what you're asking the macro to do is to type that proc onto the stack as if you'd typed it. You don't need a % because the proc is the text you're asking be typed, not a command to the macro language interpreter itself.
SAS Macro language and SAS Base are two essentially separate languages - the latter is the core of SAS, the former is a helper that can make it easier to do certain repetitive things. They're only loosely integrated.
The %let or %put are macro statements: they are not the same thing as the put you can use in the data step. They share the name and basic idea of functionality, but nothing else any more than printf in c and printf in r share in common.
For the same reason that I don't have to type <> around the words in my webpage when I am editing the HTML. The words in my webpage are not HTML commands the same way that SAS code statements are not commands to the SAS macro processor.