OK I read few topics on that one and still am stumped - apologies in advance if it's obvious for some of you.
The difference in my code is that I try create a macro variables iteratively. I think I manage to do that but the dreaded %put tells me otherwise.
I tried several things around %global but nothing really works (I tried symput instead of symputx).
My code is simple.
%macro ALLx ;
%let j=1 ;
%let k=2 ; run ;
%do i = 1 %to &ntrait. ;
data _NULL_ ;
set f2 ;
if par1 = &j. ;
call symputx("x&i.",est,g) ; run ;
%let j = %eval(&j.+&k.) ; run ;
%let k= %eval(&k.+1) ; run ;
%put &i. &j. &k. &&x&i. ; run ; quit ;
%end ;
%mend ALLx ;
%ALLx ;
%put &x1. &x2. &x3. &x4. &x5. &x6. ; run
the log gives me hope - I only give you the last round of iteration.
[...]
MLOGIC(ALLX): %LET (variable name is J)
SYMBOLGEN: Macro variable J resolves to 21
SYMBOLGEN: Macro variable K resolves to 7
MPRINT(ALLX): run ;
MLOGIC(ALLX): %LET (variable name is K)
SYMBOLGEN: Macro variable K resolves to 7
MPRINT(ALLX): run ;
MLOGIC(ALLX): %PUT &i. &j. &k. &&x&i.
SYMBOLGEN: Macro variable I resolves to 6
SYMBOLGEN: Macro variable J resolves to 28
SYMBOLGEN: Macro variable K resolves to 8
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable I resolves to 6
SYMBOLGEN: Macro variable X6 resolves to 6.2460106
6 28 8 6.2460106
MPRINT(ALLX): run ;
MPRINT(ALLX): quit ;
MLOGIC(ALLX): %DO loop index variable I is now 7; loop will not iterate again.
MLOGIC(ALLX): Ending execution.
I can see that variable X6 is resolve to 6.2460106 - great.
but the %put statement wipes my smile away as I got the WARNING: Apparent ...not resolved.
anyway if any of you have hints, please forward.
cheers
Th.
As previously explained your confusion is that you do not understand the relationship between the macro processor (the macro PRE processor) and SAS code. The macro processor is trying to evaluate the %PUT statement BEFORE the CALL SYMPUTX() statement has run. So the macro variable hasn't been created yet.
Does your data really have a variable named G that you are using to determine if the X&i macro variable should be created as LOCAL or GLOBAL? Or did you mean to put G in quotes so that it is character constant?
Plus your CALL SYMPUTX() is being run conditionally (because of the subsetting IF statement in the data step) so depending on the input data it might never run. Hence it might never create the macro variable.
Also why not just create the macro variables as part of the looping so you are sure the macro variable is created whether or not the data step finds a value? You could set the value to an empty string or some other default value.
%macro ALLx ;
%local i j k ;
%global ntrait;
%let j=1;
%let k=2 ;
%do i = 1 %to &ntrait. ;
%global x&i;
%let x&i=;
data _NULL_ ;
set f2 ;
if par1 = &j. ;
call symputx("x&i.",est,'g') ;
run ;
%let j = %eval(&j.+&k.);
%let k= %eval(&k.+1) ;
%put &=i &=j &=k X&i=&&x&i.. ;
%end ;
%mend ALLx ;
I am sorry, but thats really not a good way of working. Macro language is a text based find/replace pre-processor, used for generalising code. It is not a replacement for Base SAS - the programming language, which has all datatypes/functions etc. Your just creating code which will cause you headaches and break half the time. Do you data processing in a dataset, I can't really provide code as you have not provided test data/required output, but what I can say is there is a fair bit wrong with the code and the understanding.
First, you have lots of run; statements in there, some will cause problems, others are just irrelevant.
The key problem here however is your mixing datastep (Base SAS) with Macro which operate at different levels and so are incompatible. Lets take an example, Macro is resolved first by the macro pre-processor so your code becomes (note ntrait is never defined - another issue in the code):
data _NULL_ ; set f2 ; if par1=1; call symputx("x1",est,g) ; run ; ; run ; ; run ; ; run ; quit ;
This code is repeated to the number in ntrait.
If you would like working code, please provide test data in the form of datastep:
And show what you want out at the end, I am 100% certain there is a simpler more robust approach.
Hi RW9
Thanks for the quick answer.
Couple of things: I did not provide the whole code as it would be too cumbersome, but trust me ntrait is well defined.. Also the multiple 'run' statements are the results of several try and fail; I usually keep them short.
The macro however badly built it can be seem to give me the correct result. My question is more why when I want to print %put &X6. I get the Warning: apparent symbolic reference not resolved?
Look at the code generated:
data _NULL_ ; set f2 ; if par1=1; call symputx("x1",est,g) ; run ; ; run ; ; run ; ; run ; quit ;
G is not quoted in the call symputx. I would still highly recommend you alter the code, just as something might work, does not make it a good idea, robust, simple or repeatable.
Apart from what has already been said by @RW9, you are using here a loop that
read several times the same dataset unecessarily increasing the run time.
Sine the input dataset is always the same, you only need to read it once and hence
there is no need to use a macro here.
Tell us what you wan't to do and we'll provide a non macro way to solve yuor problem.
Nothing wrong with macros but as @RW9 they are just a text replacement tool
and should not be used to manipulate data.
@MrTh wrote:
the log gives me hope - I only give you the last round of iteration.
[...] MLOGIC(ALLX): %LET (variable name is J) SYMBOLGEN: Macro variable J resolves to 21 SYMBOLGEN: Macro variable K resolves to 7 MPRINT(ALLX): run ; MLOGIC(ALLX): %LET (variable name is K) SYMBOLGEN: Macro variable K resolves to 7 MPRINT(ALLX): run ; MLOGIC(ALLX): %PUT &i. &j. &k. &&x&i. SYMBOLGEN: Macro variable I resolves to 6 SYMBOLGEN: Macro variable J resolves to 28 SYMBOLGEN: Macro variable K resolves to 8 SYMBOLGEN: && resolves to &. SYMBOLGEN: Macro variable I resolves to 6 SYMBOLGEN: Macro variable X6 resolves to 6.2460106 6 28 8 6.2460106 MPRINT(ALLX): run ; MPRINT(ALLX): quit ; MLOGIC(ALLX): %DO loop index variable I is now 7; loop will not iterate again. MLOGIC(ALLX): Ending execution.
I can see that variable X6 is resolve to 6.2460106 - great.
but the %put statement wipes my smile away as I got the WARNING: Apparent ...not resolved.
There is no such WARNING in your SASLOG.
apologies PaigeMiller
I did not put the log warning.
MLOGIC(ALLX): Ending execution.
WARNING: Apparent symbolic reference X1 not resolved.
WARNING: Apparent symbolic reference X2 not resolved.
WARNING: Apparent symbolic reference X3 not resolved.
WARNING: Apparent symbolic reference X4 not resolved.
WARNING: Apparent symbolic reference X5 not resolved.
WARNING: Apparent symbolic reference X6 not resolved.
167 %put &x1. &x2. &x3. &x4. &x5. &x6. ; run ;
&x1. &x2. &x3. &x4. &x5. &x6.
As previously explained your confusion is that you do not understand the relationship between the macro processor (the macro PRE processor) and SAS code. The macro processor is trying to evaluate the %PUT statement BEFORE the CALL SYMPUTX() statement has run. So the macro variable hasn't been created yet.
Does your data really have a variable named G that you are using to determine if the X&i macro variable should be created as LOCAL or GLOBAL? Or did you mean to put G in quotes so that it is character constant?
Plus your CALL SYMPUTX() is being run conditionally (because of the subsetting IF statement in the data step) so depending on the input data it might never run. Hence it might never create the macro variable.
Also why not just create the macro variables as part of the looping so you are sure the macro variable is created whether or not the data step finds a value? You could set the value to an empty string or some other default value.
%macro ALLx ;
%local i j k ;
%global ntrait;
%let j=1;
%let k=2 ;
%do i = 1 %to &ntrait. ;
%global x&i;
%let x&i=;
data _NULL_ ;
set f2 ;
if par1 = &j. ;
call symputx("x&i.",est,'g') ;
run ;
%let j = %eval(&j.+&k.);
%let k= %eval(&k.+1) ;
%put &=i &=j &=k X&i=&&x&i.. ;
%end ;
%mend ALLx ;
It happens because you wrote
call symputx("x&i.",est,g);
the problem being that your g is seen as a reference to a datastep variable, not a constant expression. Try again with
call symputx("x&i.",est,'g');
You need to understand how CALL SYMPUT works.
/* This works */
data x;
x='December';
call symput('var',x);
proc print; /* Boundary */
%PUT "Report for &var";
run;
/* This will not work */
%symdel var;
data x;
x='December';
call symput('var',x);
/* No step boundary */
%PUT "Report for &var";
run;
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.