I dont understand what is going on in my SAS code. The code behaves as expected, but only during the first time it compiles, i.e. the table called \'SummaryTable\' shows the
It doesn't jump out what, exactly is wrong. Are you getting any ERRORS when you run? The fact that it runs the first time and not the second tells me there might be something more than scoping of a macro variable.
You can declare MyLogLik
local in %ModelsSummary
with %local MyLogLik;
.
I think you're running into issue's with how call execute is working and when the macro variables are resolving. My reasoning for that is if you call the macro individually via %ModelsSummary(..) the error does not occur. I don't know why it's occurring and hopefully someone has a better response for you. A workaround is to use unique macro variables, i.e. add &count at the end of MyLogLik macro variable.
%macro ModelsSummary(Count,Var,Param);
proc sql;
select _LNLIKE_ into :MyLogLik&count from parameters&Count;
insert into SummaryTable (ModelNumber,ModelVariables,NumParameters, LogLik) values (&Count,"&Var",&Param, &&MyLogLik&count);
drop table parameters&Count;
quit;
%mend;
Short answer is try wrapping your macro call inside %NRSTR(). This will be a long explanation. But the macro language is hard. And the timing of call execute when used to call macros makes it trickier. Most of below is what I learned from many SAS-L posts/papers/discussions by Ian Whitlock. If you google "Ian Whitlock Call Execute" you will find much better explanations than I can provide, but here is a shot.
Here is an example of a simple macro that works. It uses data step PUT statements to write a list of names to the log. PROC SQL is used to generate the list of names and store it in a macro variable &list. Note that the macro variable is declared to be local to the macro.
%macro ListNames(sex=F);
%local list;
proc sql noprint;
select name into :List separated by " "
from sashelp.class
where sex="&sex"
;
quit;
data list;
list="&list";
put "Inside Macro " list=;
run;
%mend ListNames;
Here is the log from calling the macro twice (without call execute):
20 %listNames(sex=F)
Inside Macro list=Alice Barbara Carol Jane Janet Joyce Judy Louise Mary
NOTE: The data set WORK.LIST has 1 observations and 1 variables.
21 %listNames(sex=M)
Inside Macro list=Alfred Henry James Jeffrey John Philip Robert Ronald Thomas William
NOTE: The data set WORK.LIST has 1 observations and 1 variables.
Here is an example of calling the macro twice using call execute that does not work. Similar to the way your code does not work. First is the code, then the log, then my explanation:
data _null_;
input sex $1;
call execute('%ListNames(sex='||sex||')');
cards;
F
M
;
run;
%put OUTSIDE MACRO list=&list;
%*cleanup;
%symdel List;
LOG:
30 data _null_;
31 input sex $1;
32 call execute('%ListNames(sex='||sex||')');
33 cards;
NOTE: CALL EXECUTE generated line.
36 ;
1 + proc sql noprint;
1 + select name into :List separated by " " from
sashelp.class where sex="F" ;
1 +
quit;
1 +
data list; list=""; put "Inside Macro " list=; run;
Inside Macro list=
NOTE: The data set WORK.LIST has 1 observations and 1 variables.
2 + proc sql noprint;
2 + select name into :List separated by " " from
sashelp.class where sex="M" ;
2 +
quit;
2 +
data list; list=""; put "Inside Macro " list=; run;
Inside Macro list=
NOTE: The data set WORK.LIST has 1 observations and 1 variables.
37 run;
38 %put OUTSIDE MACRO list=&list;
OUTSIDE MACRO list=Alfred Henry James Jeffrey John Philip Robert Ronald Thomas William
39
Explanation:
Notice that there are no warnings or errors in the log, yet the code did not "work". The value of &list inside the macro is always empty. And interestingly, even though the macro declares &list to be local, &list is ultimately created as a global macro variable. Surprising?
The job of call execute, and the macro language, is to generate code. When you use call execute to invoke a macro (as above), the macro executes and generates whatever SAS code, and dumps it on the input stack. All of code is generated before any of the code is executed.
In the example above, the PROC SQL step is generated, and the DATA LIST step is generated. But the DATA LIST step is generated before the PROC SQL step has executed! Normally, would think the PROC SQL step would be executed, and would populate &list, and then the DATA LIST step would be compiled and executed. But remember that this macro was invoked by CALL EXECUTE, inside of a DATA STEP that is still running. SAS cannot execute PROC SQL at the same time as the main DATA STEP is executing (ignoring newer DOSUBL function and similar). So at the time the DATA LIST code is generated, the macro variable &list has not been populated. It is null. If the macro did not have a %local statement, I would get a warning about macro variable not resolving (as you did).
So why does the macro variable resolve outside of the macro (returning list of males)? Note that the code generated by the macro is actually executed outside of the macro. That is, call execute invoked the macro, but the code generated is simply put on the input stack. When it executes, it is in open code. So it generates a global macro variable. Note you can see all the code generated by CALL EXECUTE as it is prefaced with + in the log.
Solution is to wrap the macro trigger in %NRSTR(). When you do this, call execute will not actually invoke the macro. But it will generate the macro call, and put the macro call on the input stack. Then when the macro executes, the PROC SQL step will be executed before the DATA LIST step.
Here's code:
data _null_;
input sex $1;
call execute('%nrstr(%%)ListNames(sex='||sex||')');
cards;
F
M
;
run;
And the log:
49 data _null_;
50 input sex $1;
51 call execute('%nrstr(%%)ListNames(sex='||sex||')');
52 cards;
NOTE: CALL EXECUTE generated line.
55 ;
1 + %ListNames(sex=F)
Inside Macro list=Alice Barbara Carol Jane Janet Joyce Judy Louise Mary
NOTE: The data set WORK.LIST has 1 observations and 1 variables.
2 + %ListNames(sex=M)
Inside Macro list=Alfred Henry James Jeffrey John Philip Robert Ronald Thomas William
NOTE: The data set WORK.LIST has 1 observations and 1 variables.
%NRSTR() is used to hide the macro trigger from CALL EXECUTE. Note that call execute only generates the two macro calls (shown in log with + prefix). It does not actually execute the macros. The macros are executed after the data step that used CALL EXECUTE. So the code generated by the macros executes as one would hope (the PROC SQL step is executed before the DATA LIST step is compiled and executed).
Key point is that when you use CALL EXECUTE to invoke a macro, if that macro uses DATA STEP or PROC SQL code to generate macro variables, it's a good idea to use %NRSTR() to delay the execution of the macro.
HTH