BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
JROTE
Calcite | Level 5

I've got a problem trying to deal with variable names with special characters (actually ending with +).

I am using options validvarname=any but when I use 'proc freq' or 'put' on these variable names, I can't get them to work because they thinks it's part of an expression/sum.

 

Also tried doing a workaround where I change the names of the variables, but that's failing too because any function doesn't like the variable name as an input.

 

Any ideas?

 

My code is below.

It gets the variable names using proc contents, and uses macro variables to loop through numeric and char variables separately.

The errors come when trying to do the proc freq and put, so basically need to know how to get these functions to read the full variable name without truncating/removing the + from end of variable name.

I am seeking to apply to a dataset I didn't create which has the variable names with + at the end - obviously I wouldn't choose to name my variables like that!!!:

 

OPTIONS VALIDVARNAME=ANY MLOGIC MPRINT SYMBOLGEN;



data shoes_2;

set sashelp.shoes;

format 'new_var_30+'n 8.;

'new_var_30+'n = 1000;

run;



%macro check_static(LName, DSName);



proc contents data=&LName..&DSName. noprint out=pc(keep=memname name type length nobs);

run;



/* Numeric Variables */

proc sql noprint;

select name into : num_vars separated by " "

from pc

where type = 1;

quit;



proc sql noprint;

select count(*) into : nvars_num

from pc

where type = 1;

quit;



/* Character Variables */

proc sql noprint;

select name into : char_vars separated by " "

from pc

where type = 2;

quit;



proc sql noprint;

select count(*) into : nvars_char

from pc

where type = 2;

quit;





/* Create empty dataset */

proc sql;

create table &DSName._Static

(

Dataset char length 32 format $20.,

Variable char length 32 format $20.,

Is_Static num length 8 format 3.,

Static_Value char length 20 format $20.

);

quit;



/* Loop for numeric variables*/

%do i=1 %to &nvars_num.;

              %let var = %scan(&num_vars., &i., ' ');

             

              proc freq noprint data=&LName..&DSName. order=freq;

              tables &var. / missing out=pf;

              run;

             

              data pf_one;

              set pf(obs=1);

              Variable = "&var.";

              run;

             

              proc sql;

              create table num_data as select

              a.memname as Dataset format $20.,

              a.name as Variable format $20.,

              case when b.count=a.nobs then 1 else 0 end as Is_Static format 3.,

              case when b.count=a.nobs then put(b.&var.,20.) else "" end as Static_Value format $20.

              from pc as a

              left join pf_one as b

              on a.name = b.variable

              where a.name = "&var.";

              quit;

             

              proc append base=&DSName._Static

                             data=num_data force;

              run;

             

%end;



/* Loop for character variables*/

%do j=1 %to &nvars_char.;

              %let var = %scan(&char_vars., &j., ' ');

             

              proc freq noprint data=&LName..&DSName. order=freq;

              tables &var. / missing out=pf;

              run;

             

              data pf_one;

              set pf(obs=1);

              Variable = "&var.";

              run;

             

              proc sql;

              create table char_data as select

              a.memname as Dataset format $20.,

              a.name as Variable format $20.,

              case when b.count=a.nobs then 1 else 0 end as Is_Static format 3.,

              case when b.count=a.nobs then put(b.&var.,$20.) else "" end as Static_Value format $20.

              from pc as a

              left join pf_one as b

              on a.name = b.variable

              where a.name = "&var.";

              quit;

             

              proc append base=&DSName._Static

                             data=char_data force;

              run;

             

%end;



proc sort data=&DSName._Static;

by Variable;

run;



%mend;



%check_static(work, shoes_2);

1 ACCEPTED SOLUTION

Accepted Solutions
Reeza
Super User

This is part of your problem.

/* Numeric Variables */
proc sql noprint;
select name into : num_vars separated by " "
from pc
where type = 1;
quit;


Your macro variables are not being created correctly to reference variables with + at the end. Look at the NLITERAL function to get them selected correctly. When debugging with macro code, remember to use the MPRINT/MLOGIC option and check each step during the development.

/* Numeric Variables */
proc sql noprint;
select nliteral(name) into : num_vars separated by " "
from pc
where type = 1;
quit;

@JROTE wrote:

I've got a problem trying to deal with variable names with special characters (actually ending with +).

I am using options validvarname=any but when I use 'proc freq' or 'put' on these variable names, I can't get them to work because they thinks it's part of an expression/sum.

 

Also tried doing a workaround where I change the names of the variables, but that's failing too because any function doesn't like the variable name as an input.

 

Any ideas?

 

My code is below.

It gets the variable names using proc contents, and uses macro variables to loop through numeric and char variables separately.

The errors come when trying to do the proc freq and put, so basically need to know how to get these functions to read the full variable name without truncating/removing the + from end of variable name.

I am seeking to apply to a dataset I didn't create which has the variable names with + at the end - obviously I wouldn't choose to name my variables like that!!!:

 

OPTIONS VALIDVARNAME=ANY MLOGIC MPRINT SYMBOLGEN;



data shoes_2;

set sashelp.shoes;

format 'new_var_30+'n 8.;

'new_var_30+'n = 1000;

run;



%macro check_static(LName, DSName);



proc contents data=&LName..&DSName. noprint out=pc(keep=memname name type length nobs);

run;



/* Numeric Variables */

proc sql noprint;

select name into : num_vars separated by " "

from pc

where type = 1;

quit;



proc sql noprint;

select count(*) into : nvars_num

from pc

where type = 1;

quit;



/* Character Variables */

proc sql noprint;

select name into : char_vars separated by " "

from pc

where type = 2;

quit;



proc sql noprint;

select count(*) into : nvars_char

from pc

where type = 2;

quit;





/* Create empty dataset */

proc sql;

create table &DSName._Static

(

Dataset char length 32 format $20.,

Variable char length 32 format $20.,

Is_Static num length 8 format 3.,

Static_Value char length 20 format $20.

);

quit;



/* Loop for numeric variables*/

%do i=1 %to &nvars_num.;

              %let var = %scan(&num_vars., &i., ' ');

             

              proc freq noprint data=&LName..&DSName. order=freq;

              tables &var. / missing out=pf;

              run;

             

              data pf_one;

              set pf(obs=1);

              Variable = "&var.";

              run;

             

              proc sql;

              create table num_data as select

              a.memname as Dataset format $20.,

              a.name as Variable format $20.,

              case when b.count=a.nobs then 1 else 0 end as Is_Static format 3.,

              case when b.count=a.nobs then put(b.&var.,20.) else "" end as Static_Value format $20.

              from pc as a

              left join pf_one as b

              on a.name = b.variable

              where a.name = "&var.";

              quit;

             

              proc append base=&DSName._Static

                             data=num_data force;

              run;

             

%end;



/* Loop for character variables*/

%do j=1 %to &nvars_char.;

              %let var = %scan(&char_vars., &j., ' ');

             

              proc freq noprint data=&LName..&DSName. order=freq;

              tables &var. / missing out=pf;

              run;

             

              data pf_one;

              set pf(obs=1);

              Variable = "&var.";

              run;

             

              proc sql;

              create table char_data as select

              a.memname as Dataset format $20.,

              a.name as Variable format $20.,

              case when b.count=a.nobs then 1 else 0 end as Is_Static format 3.,

              case when b.count=a.nobs then put(b.&var.,$20.) else "" end as Static_Value format $20.

              from pc as a

              left join pf_one as b

              on a.name = b.variable

              where a.name = "&var.";

              quit;

             

              proc append base=&DSName._Static

                             data=char_data force;

              run;

             

%end;



proc sort data=&DSName._Static;

by Variable;

run;



%mend;



%check_static(work, shoes_2);


 

View solution in original post

5 REPLIES 5
Reeza
Super User

This is part of your problem.

/* Numeric Variables */
proc sql noprint;
select name into : num_vars separated by " "
from pc
where type = 1;
quit;


Your macro variables are not being created correctly to reference variables with + at the end. Look at the NLITERAL function to get them selected correctly. When debugging with macro code, remember to use the MPRINT/MLOGIC option and check each step during the development.

/* Numeric Variables */
proc sql noprint;
select nliteral(name) into : num_vars separated by " "
from pc
where type = 1;
quit;

@JROTE wrote:

I've got a problem trying to deal with variable names with special characters (actually ending with +).

I am using options validvarname=any but when I use 'proc freq' or 'put' on these variable names, I can't get them to work because they thinks it's part of an expression/sum.

 

Also tried doing a workaround where I change the names of the variables, but that's failing too because any function doesn't like the variable name as an input.

 

Any ideas?

 

My code is below.

It gets the variable names using proc contents, and uses macro variables to loop through numeric and char variables separately.

The errors come when trying to do the proc freq and put, so basically need to know how to get these functions to read the full variable name without truncating/removing the + from end of variable name.

I am seeking to apply to a dataset I didn't create which has the variable names with + at the end - obviously I wouldn't choose to name my variables like that!!!:

 

OPTIONS VALIDVARNAME=ANY MLOGIC MPRINT SYMBOLGEN;



data shoes_2;

set sashelp.shoes;

format 'new_var_30+'n 8.;

'new_var_30+'n = 1000;

run;



%macro check_static(LName, DSName);



proc contents data=&LName..&DSName. noprint out=pc(keep=memname name type length nobs);

run;



/* Numeric Variables */

proc sql noprint;

select name into : num_vars separated by " "

from pc

where type = 1;

quit;



proc sql noprint;

select count(*) into : nvars_num

from pc

where type = 1;

quit;



/* Character Variables */

proc sql noprint;

select name into : char_vars separated by " "

from pc

where type = 2;

quit;



proc sql noprint;

select count(*) into : nvars_char

from pc

where type = 2;

quit;





/* Create empty dataset */

proc sql;

create table &DSName._Static

(

Dataset char length 32 format $20.,

Variable char length 32 format $20.,

Is_Static num length 8 format 3.,

Static_Value char length 20 format $20.

);

quit;



/* Loop for numeric variables*/

%do i=1 %to &nvars_num.;

              %let var = %scan(&num_vars., &i., ' ');

             

              proc freq noprint data=&LName..&DSName. order=freq;

              tables &var. / missing out=pf;

              run;

             

              data pf_one;

              set pf(obs=1);

              Variable = "&var.";

              run;

             

              proc sql;

              create table num_data as select

              a.memname as Dataset format $20.,

              a.name as Variable format $20.,

              case when b.count=a.nobs then 1 else 0 end as Is_Static format 3.,

              case when b.count=a.nobs then put(b.&var.,20.) else "" end as Static_Value format $20.

              from pc as a

              left join pf_one as b

              on a.name = b.variable

              where a.name = "&var.";

              quit;

             

              proc append base=&DSName._Static

                             data=num_data force;

              run;

             

%end;



/* Loop for character variables*/

%do j=1 %to &nvars_char.;

              %let var = %scan(&char_vars., &j., ' ');

             

              proc freq noprint data=&LName..&DSName. order=freq;

              tables &var. / missing out=pf;

              run;

             

              data pf_one;

              set pf(obs=1);

              Variable = "&var.";

              run;

             

              proc sql;

              create table char_data as select

              a.memname as Dataset format $20.,

              a.name as Variable format $20.,

              case when b.count=a.nobs then 1 else 0 end as Is_Static format 3.,

              case when b.count=a.nobs then put(b.&var.,$20.) else "" end as Static_Value format $20.

              from pc as a

              left join pf_one as b

              on a.name = b.variable

              where a.name = "&var.";

              quit;

             

              proc append base=&DSName._Static

                             data=char_data force;

              run;

             

%end;



proc sort data=&DSName._Static;

by Variable;

run;



%mend;



%check_static(work, shoes_2);


 

JROTE
Calcite | Level 5

Thanks Reeza - that has sorted my problem.

Much appreciated!

Tom
Super User Tom
Super User

Easiest solution is to stop making names like that. What purpose does it serve?  

Use VALIDVARNAME=V7 and then SAS will not allow you make names that are hard to deal with.

 

If you are forced to use such names by someone then make sure you are using name literals when referencing them.

proc sql noprint;
  select case when (type=1) then nliteral(name) else ' ' end
       , case when (type=2) then nliteral(name) else ' ' end
       , sum( type=1 ) format=32.
       , sum( type=2 ) format=32.
  into :num_vars separated by ' '
     , :char_vars separated by ' '
     , :nvars_num trimmed
     , :nvars_char trimmed
  from pc
;
quit;

...

%let var = %scan(&char_vars., &j., %str( ), q);
JROTE
Calcite | Level 5

Thanks Tom; that's very useful.

 

Tell me about it - I certainly didn't create the variable names with + sign at the end, and until yesterday didn't know it was possible.

 

At least I will know how to deal with it in future.

 

Tom
Super User Tom
Super User

Make sure to update the code that is pulling the names back out of the macro variable using %SCAN().

Your original code is treating both space and single quote as delimiters. So if NLITERAL() decided to use single quotes to because the name contained double quote character or macro triggers & or % then your %SCAN() call will generate wrong strings.

 

If the names are the result of PROC IMPORT converting column headers from some report into names then perhaps just changing the VALIDVARNAME option to V7 will prevent the strange names from being created.

SAS Innovate 2025: Call for Content

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!

Submit your idea!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 5 replies
  • 1658 views
  • 2 likes
  • 3 in conversation