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

I have the following listing of dataset names and thier dataset labels in a dataset callef "listfiles" on SAS EG v 5.1 :

 

memnamememlabel
CHECKING 
LISTFILES 
NOVNot sorted data
NOV_1Nov_1 dataset that is sorted
SORTED_NOV 
T 
_PRODSAVAIL 

 

The formats of both columns are length of 32 bytes.

 

I am writing a macro to retrieve the dataset label giving the dataset name as a parameter, for the purpose of using the dataset lable as title in proc print. I wrote the following code:

 

options symbolgen ;

%macro label(memname=) ;
%global &titleone   ;
proc sql;
select trim(memlabel) into :"&titleone." length = 256.
from listfiles 
where trim(memname) = &memname ;
quit;
%mend label ;

%label (memname= "NOV" ) ;

%put  &titleone ;

But I keep getting the error:

 

 

SYMBOLGEN: Macro variable TITLEONE resolves to Not sorted data

  

SYMBOLGEN: Macro variable TITLEONE resolves to Not sorted data

 NOTE: Line generated by the macro variable "TITLEONE".

32 "Not sorted data

_________________________________________________________________________________________________________________________

22

76

SYMBOLGEN: Macro variable MEMNAME resolves to "NOV"

ERROR 22-322: Expecting a name.

ERROR 76-322: Syntax error, statement will be ignored.

 

Appreciate help on fixing this. I think it must be something to do with macro quoting....but I am not able to nail it.

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

Is the name of the macro variable you want to populate TITLEONE? Or does the macro variable named TITLEONE contain the name that you want to use for the macro variable that you are going to create?  I would assume that you want the former so you need to change the %GLOBAL statement to:

%global titleone;

Then in the SELECT statement you will also just use the name of the variable.

To trim the results of the select when writing into the macro variable use the TRIMMED keyword of the INTO syntax .

select memlabel into :titleone trimmed

In your WHERE clause  to compare your dataset variable to a character literal. Normally you do NOT include quotes in macro variable values so you should add the quotes when they are needed where you are using the macro variable's value.

where memname = "&memname"

You also might want to make sure to account for case issue.  What if the user used Nov instead of NOV? In SAS code like the DATA= option on PROC PRINT the case wouldn't matter.  But when comparing character strings "Nov" and "NOV" are different values.

What do you want TITLEONE to have when the member name is not found?

Also what did you want to use for those members that do not have labels?

 

You probably want something like this.

 

%macro label(memname=) ;
%global titleone ;
%let titleone=&memname ;
proc sql noprint;
select coalesce(memlabel,memname) into :titleone trimmed
  from listfiles
  where upcase(memname) = %upcase("&memname")
;
quit;
%mend label ;

%let dsname=nov;
%label (memname= &dsname) ;
Title1 "PROC PRINT for &titleone";
proc print data=&dsname ;
run;

 

View solution in original post

6 REPLIES 6
andreas_lds
Jade | Level 19

In the into-clause in proc sql you have to use the name of the macro variable without ampersand and quotes. 

 


options symbolgen ;

%macro label(memname=) ;
  %global &titleone   ;

  proc sql noprint;
    select trim(memlabel) into :titleone trimmed
    from listfiles 
    where trim(memname) = "&memname";
  quit;
%mend label ;

%label (memname= NOV ) ;

%put  &titleone ;
Tom
Super User Tom
Super User

Is the name of the macro variable you want to populate TITLEONE? Or does the macro variable named TITLEONE contain the name that you want to use for the macro variable that you are going to create?  I would assume that you want the former so you need to change the %GLOBAL statement to:

%global titleone;

Then in the SELECT statement you will also just use the name of the variable.

To trim the results of the select when writing into the macro variable use the TRIMMED keyword of the INTO syntax .

select memlabel into :titleone trimmed

In your WHERE clause  to compare your dataset variable to a character literal. Normally you do NOT include quotes in macro variable values so you should add the quotes when they are needed where you are using the macro variable's value.

where memname = "&memname"

You also might want to make sure to account for case issue.  What if the user used Nov instead of NOV? In SAS code like the DATA= option on PROC PRINT the case wouldn't matter.  But when comparing character strings "Nov" and "NOV" are different values.

What do you want TITLEONE to have when the member name is not found?

Also what did you want to use for those members that do not have labels?

 

You probably want something like this.

 

%macro label(memname=) ;
%global titleone ;
%let titleone=&memname ;
proc sql noprint;
select coalesce(memlabel,memname) into :titleone trimmed
  from listfiles
  where upcase(memname) = %upcase("&memname")
;
quit;
%mend label ;

%let dsname=nov;
%label (memname= &dsname) ;
Title1 "PROC PRINT for &titleone";
proc print data=&dsname ;
run;

 

constliv
Obsidian | Level 7

Tom,

 

Well done ! Thank you for the detailed response, which is so helpful and I am sure other readers will also benefit.

 

I liked the defensive programming aspects you brought into the solution and how you made the name of the dataset also a macro variable. Good learning points. Speaking from the other side though, sometimes managers want quick and dirty results and programmers are forced to skip features that will give robust results for want of time.

 

One small thing. I had to tweak the coalesce part of the code to print the dataset label as title if populated, the order of the arguments of the coalesce function had to be swapped as follows (memlabel first and then memname). Otherwise it was not picking up the dataset label as titile for the print output:

 

%macro label_1(memname=) ;
%global titleone ;
%let titleone=&memname ;
proc sql noprint;
select coalesce(memlabel, memname) into :titleone trimmed
  from listfiles
  where upcase(memname) = %upcase("&memname")
;
quit;
%mend label_1 ;

%let dsname=nov_1;
%label_1 (memname= &dsname) ;
%put &titleone ;
Title1 "PROC PRINT for &titleone";
proc print data=&dsname ;
run;

 

Thank you.

constliv
Obsidian | Level 7
Hi Tom,

You may want to to edit the coalesce part so that tehcnically the code is indeed the final solution.
Tom
Super User Tom
Super User

@constliv wrote:
Hi Tom,

You may want to to edit the coalesce part so that tehcnically the code is indeed the final solution.

Updated.

constliv
Obsidian | Level 7

Hi andreas_ids,

 

Your solution worked. Thank you.

 

And when I extended your solution to print titles, which is the goal of the program, I found that the below code works :

options symbolgen ;

%macro label(memname=) ;
  %global &titleone   ;

  proc sql noprint;
    select trim(memlabel) into :titleone trimmed
    from listfiles 
    where trim(memname) = "&memname";
  quit;
%mend label ;

%label (memname= NOV ) ;

title 'PROC PRINT for' &titleone  ;
proc print data = nov ;
run ;

Not sure if the community board allows two responses to be selected as 'Accepted as solution' as I would like to accept Tom's solution as well.

 

 

Thank you for taking time to help. Much appreciated.

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

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.

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
  • 6 replies
  • 5066 views
  • 2 likes
  • 3 in conversation