GLOBAL attempt a name macro variable that exists in a local environment - macros

Good morning everyone.
I am trying to run the following code:
%macro clearALL;
/*delete macro variables*/
data delete;
set sashelp.vmacro;
where scope eq: 'F' and name ne: 'SYS';
run;
data _null_;
set delete;
call symdel(name) ;
run;
%mend clearALL;
%Macro Test;
%do i = 1 %to 18;
%put &= Iteration : &i;
data _null_;
set work.input;
if _n_ eq &i then do;
call symput('TipoDocumento',Tipo_Id);
call symput('NroDocumento',Numero_Id);
call symput('Fecha_nacimiento',FechaNacimiento);
call symput('TipoEvaluacion',TipoEvaluacion);
call symput('ESP',ESP);
call symput('NIE',NIE);
call symput('NIE_Asociado',NIE_ASOCIADO);
call symput('Estrato',ESTRATO);
call symput('IdConsulta',IdConsulta);
call symput('TipoRespuesta',TIPO_RESPUESTA);
end;
run;
%include "D:/Data_SAS/Sguerrero/TestMomento1.sas";
%clearALL;
%end;
%Mend;
%Test;
The data test contains the variables that will be converted into macro variables to execute code in the script included with include sentence. This code uses these variables and creates global and local variables. The% clearALL macro eliminates the macro variables created in the previous iteration.
But I receive the following error message:
ERROR:% GLOBAL attempt a name (CAUSAL) that exists in a local environment.
Why the error message if the macro variables were removed with the% clearALL macro?
Thaks for helping me

Be explicit when creating the macro variables whether they are Local or Global, Replace all your Symput() with Symputx().
Example for Local:
call symputx('Estrato',ESTRATO,'L');
Example for Global:
call symputx('Estrato',ESTRATO,'G');
SymputX Documentation

Try adding %SYSMSTORECLEAR; to the beginning of your code. This will close the stored compiled macro catalog in case that was causing the error.

call symput() will create a new macro variable if the one you specified doesn't already exist. If you don't tell SAS where to create the macro variable (which requires using call symputx() instead of call symput()) then it will make the new macro variables in the current macro's scope. If you then later attempt to create a global macro variable with the same name using the %global statement you will get that error message.
You could just define the macro variables as global before trying to assign a value to the it.
%global TipoDocumento ;
Note that if you switch to using call symputx() you can tell SAS to make the macro variable in the global symbol table.
call symputx('TipoDocumento',Tipo_Id,'g');

Related

SAS Macro operations

I need to create sum of 4 variables multiple times each time with new set of variables. For e.g. A1=sum(a1,a2,a3,a4),B1=sum(b1,b2,b3,b4) & so on. So , I am trying to write a macro that will help me do it easily. Following is the code:
%macro SUM2(VAR1,var2,var3,VAR4);
data Subs_60_new;
set Subs_60;
substr(&var1,1,10)=sum(&var1,&var2,&var3,&var4);
run;
%mend sum2;
options mprint mlogic;sum2(ADDITIONAL_INFO_Q1,ADDITIONAL_INFO_Q2,ADDITIONAL_INFO_Q3,ADDITIONAL_INFO_Q4);
I am using SAS EG for the same & when I run the macro I get the following note:
NOTE: Writing TAGSETS.SASREPORT13(EGSR) Body file: EGSR
& obviously when I try to execute the macro it throws an error.
Can some one help me out?
when calling a macro, you need to precede the macro name with a % symbol, eg as follows:
%macro SUM2(VAR1,var2,var3,VAR4);
data Subs_60_new;
set Subs_60;
substr(&var1,1,10)=sum(&var1,&var2,&var3,&var4);
run;
%mend sum2;
options mprint mlogic;
%sum2(ADDITIONAL_INFO_Q1,ADDITIONAL_INFO_Q2,ADDITIONAL_INFO_Q3,ADDITIONAL_INFO_Q4);
The NOTE is harmless. It is ERRORs and WARNINGs in general that you should be concerned with.
I'd point out that this will probably still throw an error, as you are trying to replace characters in a variable (&var1) that appears as though it should contain a numeric field (being part of a sum function). Given your description of what you are trying to achieve, I'd suggest adding the new variable name as another macro parameter - as follows:
%macro SUM2(VAR1,var2,var3,VAR4,varname);
data Subs_60_new;
set Subs_60;
&varname=sum(&var1,&var2,&var3,&var4);
run;
%mend sum2;
options mprint mlogic;
%sum2(ADDITIONAL_INFO_Q1,ADDITIONAL_INFO_Q2
,ADDITIONAL_INFO_Q3,ADDITIONAL_INFO_Q4
,MyNewVariable);

substr function with macro variable name

I am trying to use substr function in SAS macros like this:
%let hg=Name;
data gg_;
set sashelp.class;
gh=%substr(&hg,1,3);
run;
and also I tried
data gg_;
set sashelp.class;
gh=%sysfunc(substr(&hg,1,3));
run;
Here Name is the variable in sashelp.class
But I do not get the first three chars from Name variable into gh.
How do I do it?
You are mixing macro and data step logic.
Since it is a data step, use the SUBSTR() function, not %substr. If the macro variable consists of the text you want to extract then quote it, otherwise leave the macro variable unquoted.
gh=substr(&hg, 1, 3);
Note: edited to reflect comment.
If you are creating a dataset inside a macro function then you want to use the normal sas function so you just need to use substr() instead of %substr().
%let hg=Name;
data gg_;
set sashelp.class;
gh=substr(&hg,1,3);
run;

SAS Macro Variable Quoted Concatenation

I am debugging a macro I am writing that will treat a string as either a prefix or suffix of a dataset name based on user input. Then, the quoted result will be fed into another process downstream.
So if the user says Type=1 and provides the string 'data_', the output of the resulting macro variable will be 'data_%'.
I've tried a few different iterations of the below code, but can't quite get it....any help would be greatly appreciated. Thanks.
%let Type=1;
%let TableName=data_;
data _null_;
if &Type=1 then
call symput('qTableName',%unquote(%str(%')(cats(&TableName.,"%"))%str(%')));
else if &Type=2 then
call symput('qTableName',%unquote(%str(%')(cats("%",&TableName.))%str(%')));
run;
%put &qTableName;
Looks like you are trying to add single quotes to a macro variable.
%let TableName=data_;
%let qTableName='data_%';
So in a data step you can use CATQ().
data _null_;
call symputx('qTableName',catq('1a',cats(symget('TableName'),'%')));
run;
Or in simple macro code just use %bquote() to allow you to add ' and % without preventing macro variable expansion. But you probably want to remove the macro quoting it will cause.
%let qTableName=%unquote(%bquote('&TableName%'));
Or if you only want to add the % when &TYPE=1 then perhaps you could call the IFC() function. I believe that the %sysfunc() call will remove the macro quoting.
%let Type=1;
%let qTableName=%sysfunc(ifc(&type=1,%bquote('&TableName%'),%bquote('&TableName')));

Dynamically choose name of macro to call?

In SAS, the double/triple/etc ampersand can be used to dynamically choose which macro variable to resolve. Is there an equivalent syntax using double/triple/etc percents?
I tried %%%substr(&x,3) expecting the same resolution rules to be used (i.e. turn %% into %, then call the substring macro, then call the macro with the name of the result) but it is apparently invalid syntax.
You can use macro variable instead of fixed macro name, e.g.:
%let mname=test;
%macro test;
%put I am test.;
%mend;
%&mname

Assigning a macro variable value to a data step variable in SAS

I am calling a macro inside a data step and assigning the macro variable to a data step variable as below.
The input for the macro goes from the input dataset which has some 500 records.
%macro test(inp_var);
%global macro_var;
--- using inp_var variable here---
%if --some condition-- %then call symput('macro_var',-- some value--);
%mend;
data output;
set input;
%test(inp_var);
new_data_step_var = symget('macro_var');
run;
But it's showing the error message pointing the variable new_data_step_var - ERROR 180-322: Statement is not valid or it is used out of proper order.
No SAS macro actually executes "inside" a data step. The macro language processor and data step compiler as two different subsystems that share the code input stream. They hand off to one another as they "eat" chunks of SAS code. In the case of the original program, the language processor in SAS sees the "data" statement and hands off to the data step compiler. The embedded %test macro call is detected and the code input stream is handed to the macro processor FIRST! The macro processor expands all of the code and macro logic inside of the %test macro and then the whole stream of code is handed back to the SAS data step compiler to compile.
So %test is going to run to completion BEFORE the data step even compiles.
If you are looking to make your own subroutines in data step try proc fcmp. Otherwise, just implement your conditional logic inside of the data step as was suggested.
Re-write it using datastep if/then, not macro if/then, and don't create a macro variable, simply use a datastep variable.
%MACRO TEST(var) ;
call missing(tempvar) ;
if --some condition-- then tempvar = --some value-- ;
%MEND ;
data output ;
set input ;
%TEST(inp_var) ;
new_var = tempvar ;
drop tempvar ;
run ;
You cannot use a macro variable in the same data step where you set it with call symput.
The result of your call symput statement is only available after the data step.
So at the time the symget statement is being processed, the macro variable does not exist yet.
Also, it seems rather pointless, why don't you use a retain statement to save the value you want?
e.g.:
data output;
set input;
retain new_data_step_var;
if --some condition -- then new_data_step_var = --some value--;
run;
Macros that contain a proc or a data step are not executable inside of a data step. Macros are not functions or subroutines; they are text, just as if you'd typed it out (just saving some time with loops and conditionals). So the contents of your macro need to either be text that could be executed inside a data step:
%macro mymacro(numiters);
*this macro would be easier to do in an array, but it is an example;
%local t;
%do t = 1 to &numiters.;
x&t. = mean(y&t.,z&t.);
%end;
%mend mymacro;
data output;
set input;
%mymacro(5);
run;
In that case, it is easier (and more stylistically correct) to not store a value in a macro variable. Simply contain the result in a data step variable, and if needed pass that variable's name as one of your arguments.
There are also function-style macros, that actually return a value to the data step (or in this case, return text that equates to a value). They can be used on the right side of an equal sign.
%macro xtothey(in,power);
%local t;
&in.
%do t = 1 to &power-1;
*&in.
%end;
;
%mend myfunctionmacro;
data output;
set input;
y = %xtothey(x,4);
run;
That would actually be more easily done in PROC FCMP (which compiles functions and subroutines), but sometimes macros are better for this (or you might not know FCMP well).
Finally, some macros require procs or data steps of their own. In those cases, unless you're using some FCMP elements such as DOSUBL, you will need to store the value somewhere, whether it is in a dataset or a macro. In those cases, you must run the macro prior to the datastep where you want the value - but you only get one (or a finite number of) return values. You don't get one per row unless you go to some extreme lengths, which usually can be done better without using macro variables. I would argue the below is bad form, as you almost always can do it better without using macro variables - but this is how you would do it if you needed to. FCMP with DOSUBL would probably be the superior choice.
%macro findmode(dset,var,outvar);
proc means data=&dset;
var &var.;
output out=_tempset mode(&var.)=&var._mode;
run;
data _null_;
set _tempset;
call symputx("&outvar.",&var._mode);
run;
%mend findmode;
%findmode(sashelp.class,weight,wtmode);
data output;
set input;
mode=&wtmode;
run;