Priyesh Sura
Priyesh Sura

Reputation: 113

Literal contains unmatched quote. (SAS)

I am trying to get the values passed in a macro variable and put quotes around it. i.e. space separated list to space separated quoted list. e.g. given below. I have used the following approach given by Jeff in one of my earlier post.

data test;
   id =1; _var="ABC"; output;
   id =1; _var="DEF"; output;
   id =1; _var="UVW"; output;
   id =2; _var="UVW"; output;
   id =3; _var="ABC"; output;
   id =3; _var="UVW"; output;
   id =3; _var="XYZ"; output;
   id =4; _var="ABC"; output;
   id =4; _var="XYZ"; output;
run;

%macro __test1(_byvar=, _qnam=, _id=);
    proc sort data= test out=_test;
        by &_byvar.;

  %if %superq(_qnam) ne %then
  %do; 
            %let __tmpmv_qnam = %qsysfunc(prxchange(%bquote(s/\b/"/),-1,%bquote(&_qnam))); 
            *";
            %put ^^^^^&__tmpmv_qnam.;
      where upcase(&_id) in (&__tmpmv_qnam);
  %end;

    run;

%mend;

%__test1 (_byvar=id ,_qnam = ABC UVW, _id=_var);

The log diaplayed following error:

SYMBOLGEN:  Macro variable _QNAM resolves to ABC UVW  
ERROR: Literal contains unmatched quote.

Please help on this one.

Upvotes: 2

Views: 9652

Answers (3)

Tom
Tom

Reputation: 51566

You seem to be making the problem harder than it is. Why not just use the INDEXW() function?

where indexw(symget('_qnam'),upcase(&_id),' ');

Or if you want to convert ABC UVW to "ABC","UVW" then a simple TRANWRD() function call will do.

where upcase(&_id) in ("%sysfunc(tranwrd(&_qnam,%str( ),","))");

However if your list could have extra spaces, if it was typed by hand for example, you will want to first remove the extra spaces.

%let _qnam=%sysfunc(compbl(&_qnam));

Upvotes: 0

Robert Penridge
Robert Penridge

Reputation: 8513

You can have an unmatched quote within a macro by using the %str() function like so:

%str(%')         <-- gives an unmatched single quote
%str(%")         <-- gives an unmatched double quote

I've applied this to your macro and reorganized/simplified it a little. Firstly you'll see that I've removed redundant %bquote() functions and changed %qsysfunc() to just %sysfunc().

I'm also building the string for the where clause and saving it to a macro variable so that the sort statement stands out more and the result of the where clause is easier to debug.

%macro __test1(_byvar=, _qnam=, _id=);

  %local list where_clause;

  %if %length(_qnam) gt 0 %then%do; 
      %let list = %sysfunc(prxchange(s/\b/%str(%")/,-1,&_qnam)); 
      %let where_clause = where upcase(&_id) in (&list);
  %end;

  proc sort data= test out=_test;
      by &_byvar.;
      &where_clause;
  run;

%mend;

Upvotes: 0

user667489
user667489

Reputation: 9569

Here's an alternative approach to adding the quotes. It's pretty basic - it doesn't check whether the input is already quoted, and there must be exactly 1 space between list items, and there must be no leading or trailing spaces in the input list, but you can adapt it to suit your needs:

%let list = a b c;
%macro qlist(LIST);
%sysfunc(compbl(
%do i = 1 %to %eval(%sysfunc(count(&LIST, %str( ))) + 1);
    "%scan(&LIST,&i)" %str( )
%end;
))
%mend qlist;

%put %qlist(&list);

Upvotes: 2

Related Questions