BookmarkSubscribeRSS Feed
analyticalepi
Calcite | Level 5

I'm recoding datasets from a longitudinal study using macros for each study group and study stage. Variable are being renamed based on another dataset, and all but the Stage variable are being recoded to character. Since the recoded datasets will later be stacked together, I want to assign the recoded group/stage dataset name generated after dynamic coding to a macro so I don't have to go through and identify which to path that particular group/stage dataset followed in the macro. Yet, the %LET statements are not working, and I think it's because I'm using macro variables to both name and assign the value to the macro. Should I be using another method?

 

Here is the portion of the macro where I'm running into this issue:

 

data &group.s&stage._1;
set &group.s&stage.;
rename var1=var2;
set;

*determining if there are any numeric variables that need to be recoded as character;
proc contents data=&group.s&stage._1 out=vars;
run;

proc sql noprint;
select min(type) into :typecheck from vars;
quit;

%if &typecheck. NE 1 %then %do;
	%LET &group.s&stage. = &group.s&stage._2;
%end;

%if &typecheck. = 1 %then %do;
	proc sql noprint;
	select name into :numvars separated by " " from vars where type=1;
	select name into :numvar1-:numvar%sysfunc(countw(&numvars.)) from vars where type=1;
	select catt(name,"N") into :recodevars separated by " " from vars where type=1;
	select catt(name,"N") into :recodevar1-:recodevar%sysfunc(countw(&recodevars.)) from vars where type=1;
	quit;

	data &group.s&stage._2;
	set &group.s&stage._1;
	array num[*] &numvars.;
	array char[*] $ &recodevars.;
	  do i=1 to dim(num);
	    char{i}=put(num{i},8.);
	  end;
	drop i &numvars.;
	rename
	%do i=1 %to %sysfunc(countw(&recodevars.));
		&&recodevar&i. = &&numvar&i.
	%end;
	;
	run;

	%LET &group.s&stage. = &group.s&stage._1;
%end;


 

 

10 REPLIES 10
ballardw
Super User

Where do you set the values for the &group and &stage variables?

What are their values?

 

Which specific %let do you think is not working?

You can check by putting a statement like %put Value of macrovariablename is &macrovariablename. ;

after the let. Read the log to see what was assigned.

 

analyticalepi
Calcite | Level 5
This code portion is part of a larger macro (ex. %macro recode (group,stage); <code> %mend;) with the group and stage variables assigned after (ex. %recode(Group1,Stage1);).
Neither %LET is working, and the log reads "WARNING: Apparent symbolic reference ICS3 not resolved." when using the %put statement such as you described.

I've tried %LET resolve(&group.s&stage.) = resolve(&group.s&stage._2); %LET eval(&group.s&stage.) = eval(&group.s&stage._2); Tried using call symput in a data step, etc. All to no avail.

ballardw
Super User

@analyticalepi wrote:
This code portion is part of a larger macro (ex. %macro recode (group,stage); <code> %mend;) with the group and stage variables assigned after (ex. %recode(Group1,Stage1);).
Neither %LET is working, and the log reads "WARNING: Apparent symbolic reference ICS3 not resolved." when using the %put statement such as you described.

I've tried %LET resolve(&group.s&stage.) = resolve(&group.s&stage._2); %LET eval(&group.s&stage.) = eval(&group.s&stage._2); Tried using call symput in a data step, etc. All to no avail.


Since your code does not show a %let for ICS3 then you are either skipping something or have not identified the correct Let statements.  Do you have any code with a macro variable reference that starts with && (two or more &) which would be indirect references and would cause a message similar to the warning you receive when the %let does not use ICS3.

 

I suspect you aren't paying close enough attention to what you are creating and are changing some values out of order.

You may want to run this code and see if it gives a better idea of what is happening:

%let group = I;
%let stage = C;

%LET &group.s&stage. = &group.s&stage._2;

%put Variable name is &group.s&stage. ;

%put Variable value is &Isc.;

 

Note: if you have multiple macros and are not careful about how macro variables are passed /used you may think you are referencing a value that is different because of the scope of the variable. This frequently happens when you use a macro variable that is not passed as part of the macro definition which you have not included.

Tom
Super User Tom
Super User

I don't know about your macro variables but this first data step looks strange.

data &group.s&stage._1;
set &group.s&stage.;
rename var1=var2;
set;

Why is the last statement SET instead of RUN?

Did you really want to try to do an obs by obs merge between &GROUP.S&STAGE and the dataset pointed to by &SYSLAST?

analyticalepi
Calcite | Level 5

My apologies, in trying to give some privacy to my client's data I edited the code but didn't closely review the edits. I will edit the code here to more closely reflect the whole macro in question. In my actual code, everything else runs but the %LET statements. Please focus on the code surrounding those and try to help me figure out why they are not running. I would appreciate your help, thanks!

PaigeMiller
Diamond | Level 26

Please use this command as the first line of your program and then run it again.

 

options mprint symbolgen mlogic;

Then, show us the LOG (the entire log for this macro portion of the code and not the hundreds of lines before the macro runs, unedited, with nothing omitted) preserving the formatting of the log so it will be easily read. How? Copy the log as text, paste it into the window that appears when you click on the </> icon. This preserves the formatting. DO NOT SKIP THIS STEP. If you send us the LOG in some other format, it is relatively useless to us.

--
Paige Miller
analyticalepi
Calcite | Level 5

I can't figure out how to edit the original post, so here is the fixed code:

 

%macro rename_recode (group,stage);

data &group.s&stage._1;
set &group.s&stage.;
rename var1=var2;
run;

*determining if there are any numeric variables that need to be recoded as character;
proc contents data=&group.s&stage._1 out=vars;
run;

proc sql noprint;
select min(type) into :typecheck from vars;
quit;

%if &typecheck. NE 1 %then %do;
	%LET &group.s&stage. = &group.s&stage._2;
%end;

%if &typecheck. = 1 %then %do;
	proc sql noprint;
	select name into :numvars separated by " " from vars where type=1;
	select name into :numvar1-:numvar%sysfunc(countw(&numvars.)) from vars where type=1;
	select catt(name,"N") into :recodevars separated by " " from vars where type=1;
	select catt(name,"N") into :recodevar1-:recodevar%sysfunc(countw(&recodevars.)) from vars where type=1;
	quit;

	data &group.s&stage._2;
	set &group.s&stage._1;
	array num[*] &numvars.;
	array char[*] $ &recodevars.;
	  do i=1 to dim(num);
	    char{i}=put(num{i},8.);
	  end;
	drop i &numvars.;
	rename
	%do i=1 %to %sysfunc(countw(&recodevars.));
		&&recodevar&i. = &&numvar&i.
	%end;
	;
	run;

	%LET &group.s&stage. = &group.s&stage._1;
%end;

%mend rename_recode;

%rename_recode(Group1,1);
%rename_recode(Group1,2);
%rename_recode(Group1,3);

Thanks!

PaigeMiller
Diamond | Level 26

Please show us the appropriate parts of the LOG, following the instructions I just gave.

--
Paige Miller
Tom
Super User Tom
Super User

But WHAT is that code doing? Please explain in words what the purpose of the code is. 

 

It sounds like you want to convert numeric variables to character.

 

But what it is the purpose of the %LET statements?  The generated macro variable are never used in the macro. And since they are not made as GLOBAL they will disappear when the macro finishes.  

Try just adding a %GLOBAL statement before the %IF/%THEN/%ELSE block.

%global &group.s&stage. ;

But it looks to me like you are setting the values backwards in the THEN and ELSE sections.  

Tom
Super User Tom
Super User

@analyticalepi wrote:

My apologies, in trying to give some privacy to my client's data I edited the code but didn't closely review the edits. I will edit the code here to more closely reflect the whole macro in question. In my actual code, everything else runs but the %LET statements. Please focus on the code surrounding those and try to help me figure out why they are not running. I would appreciate your help, thanks!


In that case you have two options for getting more help.

1) You can explain in more detail WHAT you are trying to do.  I cannot make heads or tails of what the meaning of a statement like this is:

	%LET &group.s&stage. = &group.s&stage._2;

Normally the program knows the NAME of the macro variables it wants to use and it is the VALUES that change.

 

2) Provide a working program that covers the shows the part that is not working.  To make it a fully working program either include the data (using data step and in line data) or use SASHELP tables like CLASS or CARS.

SAS Innovate 2025: Register Now

Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 10 replies
  • 2667 views
  • 0 likes
  • 4 in conversation