Given the following macro variable:
%let var = name salary work;
I need to create a macro variable which has the number of the variables in the var. In this example, this newly created macro variable is equal to 3.
The basic concept here is using the COUNTW function. You can't use that directly in a macro variable assignment though (in a %let), but you can use %SYSFUNC to enable you to use it.
%let var_count = %sysfunc(countw(&var.));
Note there are no quotation marks or similar.
Related
The following variables seem to be a standard macro in multiple SAS Code that I come across. Can someone explain the following please?
&dsin.
&dsout.
&cj_yyyymm_1.
&cj_yyyymm_2.
No, those are not "standard" macro variables. There are automatic macro variables, which you can view with
%put _automatic_;
And some other system-generated macro variables are sometimes just stored as regular global macro variables, which you can view with:
%put _global_;
or
%put _all_;
Which will print all currently defined macro variables - run it at startup and you'll see just the ones SAS defines.
What you show there are macro variables that perhaps are standard for your company, but don't have any standard meaning. I would posit that &dsin is an input dataset to a macro, and &dsout is an output dataset, and the other two are year/month stamped variables, but they don't have any official, standard definition, nor would I say those are particularly commonly seen.
Those are not generic, they are specific to your program or company but you can make educated guesses. DS is a common abbreviation for data set.
&dsin. = Input data set
&dsout. = Output data set
&cj_yyyymm_1. = some date parameter, probably like 202110
&cj_yyyymm_2. = some other date parameter....
CJ could mean something specific at your company or may reference something in your code.
I need to store in a macro variable the number of rows in a data set. So I used this:
%macro get_table_size(inset,macvar);
data _null_;
set &inset NOBS=size;
call symput("&macvar",size);
stop;
run;
%mend;
%get_table_size(LOANTAPE.INSTRUMENT_VU21,NUM_REG_INS);
%put &NUM_REG_INS;
Before my computer crashed (having to force it to reboot with SAS opened), this worked (I swear xd). But now, the macro NUM_REG_INS is not created. The log says: Apparent symbolic reference MACVAR not resolved.
So I checked the code as a data step and not a macro, like this:
data _null_;
set LOANTAPE.INSTRUMENT_VU21 NOBS=size;
call symput("macvar",size);
stop;
run;
%put &macvar
And it works. So the problem is when using this code inside a macro. Does anybody knows what could be happening here and how to fix it? And, just for the sake of curiosity, why was it working before?
Thank you, really!!
Variable scope. Look into using CALL SYMPUTX() instead of CALL SYMPUT(). It likely worked before because you either created the macro variable globally while testing and in this case you haven't. Macro variables do not exist outside the macro unless you create them as a global macro variable.
call symputx("&macvar", size, 'g');
See the documentation here
If you want to access the macro variable outside of the macro then make sure it is not defined as only local to the macro. You could use the third parameter of call symputX to force the update of a global macro variable. But then you could have trouble trying to call this macro to update a macro variable that is local to the calling macro.
Just add a line to the macro to force the macro variable to be global when it does not exist. You should also use the newer CALL SYMPUTX() function, unless you really wanted those leading spaces in the value of macro variable that the automatic conversion of SIZE to a character string would have generated by using the older CALL SYMPUT() function.
Also move the CALL SYMPUTX() to before the SET statement so it runs even if the dataset has zero observations.
%macro get_table_size(inset,macvar);
%if not %symexist(&macvar) %then %global &macvar;
data _null_;
call symputx("&macvar",size);
set &inset NOBS=size;
stop;
run;
%mend;
I am trying to create a local macro variable with the %LET statement, the value of which is a macro variable that requires multiple ampersands to resolve. SAS is not resolving the multiple ampersands before assigning the name of the local macro variable.
%macro example;
%do i=1 %to %sysevalf(&max_n);
%let dg= &&max_&i..;
{stuff happens here}
%end;
%mend;
%example;
For example, &max_1. resolves to APPLE which I use in the {stuff happens here} portion of the code. However, SAS is giving me the warning
"WARNING: Apparent symbolic reference MAX_ not resolved."
And the DG macro variable is returning &&max_1 through &&max_17. Calling &DG. at this point will return &&max_1 which will resolve to APPLE on its own, but this will not work with the syntax in the code I'm not showing.
Any idea how to make the macro variable so that &DG. will return APPLE?
(I know this is not an answer but I cannot post formatted code in comments. I will edit/remove this post afterwards).
The code you posted here is not your culprit. If I take it as-is, initialize a couple variables in front and put a %put statement where stuff happens:
%let max_1=APPLE;
%let max_n=1;
%macro example;
%do i=1 %to %sysevalf(&max_n);
%let dg= &&max_&i..;
%put &dg;
%end;
%mend;
%example;
You can copy/paste this and run it and it will print 'APPLE' to your log as expected.
There must be something more to what you are trying to do that is causing your issue.
Also, the macro variables are not resolved (or not needed to exist in parent or current scope) until macro execution time when the macro is invoked. Thus, the assignment of max_1 and max_n can occur after the macro definition and before the %example.
The behavior you are experiencing could be due to macro quoting you applied to the variables prior to the macro invocation. You can either use %unquote within the macro at callee scope, upon the macro resolution at caller scope, or determine how to process your concepts and inputs with reduced amounts of quoting.
Note: Numerically indexed macro variables are sometimes called 'macro arrays'. macro variables suffixed with symbols are sometimes called 'macro associative arrays' or 'macro objects'
When I write:
proc sql;
select count(*) into :out from sashelp.cars;
quit;
Does the macro variable out become a global or local variable?
It depends. Let's put together a test macro and see what happens
%macro test();
proc sql noprint;
select count(*) into :x from sashelp.cars;
quit;
%put IN MACRO: &x;
%mend;
options nosource nonotes;
%symdel x;
%test();
%put Out MACRO: &x;
%let x=2;
%put Out MACRO: &x;
%test();
%put Out MACRO: &x;
Creates:
IN MACRO: 428
WARNING: Apparent symbolic reference X not resolved.
Out MACRO: &x
Out MACRO: 2
IN MACRO: 428
Out MACRO: 428
So at the beginning, there was no X macro variable. The %test() macro populated a local variable. It was not available outside the macro.
After that, we set %let x=2 making X be a global variable. Then we execute the %test() macro and see that X keeps its value outside of the %test() macro.
So if it exists globally, it continues to exist and is overwritten. If it doesn't exist globally, it continues to not exist globally.
Let's take a look at the documentation to answer this compeltely.
The documentation for SQL INTO clause in the Macro language dictionary says:
Macro variables created with INTO follow the scoping rules for the %LET statement. For more information, see Scopes of Macro Variables.
So, we click on that link, and find this page - How Macro Variables are Assigned and Resolved and this page - Examples of Macro Variable Scopes.
The first page has a nice tree diagram showing the decisions SAS makes when assigning or creating a macro variable, and that might be sufficient to understand this.
The second page has some good examples and explanations:
When the macro processor executes a macro program statement that can create a macro variable (such as a %LET statement), the macro processor attempts to change the value of an existing macro variable rather than create a new macro variable. The %GLOBAL and %LOCAL statements are exceptions.
There are some very good examples on that page; what it boils down to, though, is simple. If there is already an existing macro variable with that name, it will assign the value to that macro variable, wherever that variable is - in the scope tree of the current macro, anyway. (So, a single macro executing has two symbol tables to look in: local, and global. A macro called by another macro has three: local, local to the calling macro, and global. Etc.)
However, there are a pair of related exceptions: when you specify the table to use, with %local or %global. Either of those statements referencing a macro variable before your %let or select into will cause any following statements to set that particular version - local or global - and then you're safe for sure.
It depends on where you define this marco variable, if you define it in a macro program, it is a local macro variable, otherwise it is a global macro variable.
In SAS, why cannot we write
let name = abc;
put "&name";
Why do we have to include the % sign like this:
%let name = abc;
%put &name;
Imagine I am writing the statements in the main body of the code, not inside a data step.
Also, is the second way of writing it same as:
%macro test;
%let name = abc;
%put &name;
%mend;
The %LET and %PUT statements are part of the SAS macro processor and not part of base SAS. The % (and &) triggers are what activate the macro processor and allow it to recognize that these strings need be processed before they are passed to the SAS compiler/interpreter.
You cannot use an assignment statement like
x = 3.5 ;
outside of a data step (or some proc that support these types of statements).
To your second question, if you wrap the macro statements inside of a macro definition then the main impact will be.
The macro variable NAME will be defined as local to the macro if it does not already exist.
Nothing will happen until you invoke the macro. The %macro statement begins the definition of a macro. So all of the code up to the corresponding %mend statement define the macro. To execute it you will need to invoke the macro using syntax like %test.
%let and %put are part of the SAS macro language. Macro language statements are (with one or two particular exceptions) prefixed by % to tell the SAS macro parser to operate on them.
They do entirely different things from the non-% version - except when it works out to the same thing. You can write put "&mvar."; - as long as it's in a data step (As that's a data step statement). Macro commands/functions/statements are allowed in open code sometimes (and not in others).
Writing it inside an actual macro is more-or-less the same. There are scoping issues, though; &name won't be available outside of that macro, unless it's been declared global.