BookmarkSubscribeRSS Feed
saspert
Pyrite | Level 9
Hello,
I am reworking SAS code written by a previous programmer. I am having so much trouble trying to understand his/her logic in this macro call. A bunch of user defined macros check the parameters passed by a javascript page.

The macro variables do not have any suffixes but there is a additional 0 while resolving. Any ideas why one would use it.


%macro stringGen(parm=);
%if %symexist(&parm.0) %then %do;
%do i = 1 %to &&&parm.0;
%if &i = 1 %then
%do;
%str("&&&parm&i")
%end;
%else %do;
%str(, "&&&parm&i")
%end;
%end;
%end;
%else %do;
%str("&&&parm")
%end;
%mend;

Thanks,
8 REPLIES 8
Cynthia_sas
SAS Super FREQ
Hi:
This almost looks like the kind of macro %DO loop code that was used if you were receiving multiple parameter values from a SAS/IntrNet Application Dispatcher program or multiple parameter selection from a SAS Stored Process.

For example, let's say you had a parameter or prompt for COUNTRY and the user was allowed to make up to 3 selections.

Your "front end" prompting screen would only have COUNTRY, but after the users made their multiple selections, what your program would receive would be multiple macro variables with values like this (assuming the user made 3 choices):
&COUNTRY0 = 3
&COUNTRY1 = DENMARK
&COUNTRY2 = BELGIUM
&COUNTRY3 = CANADA

So for this parameter, &COUNTRY0 holds the number of user selections. A macro %DO loop was used with the value of &COUNTRY0 as the ending point for the %DO loop.

Your macro program seems to be doing something similar by iterating a macro %DO loop from 1 to &&&parm.0 -- which implies, to me, that some macro variable like &COUNTRY0 is being used. If, for example, the value of PARM was COUNTRY, then &&&parm.0 would resolve to &COUNTRY0 --> which would resolve to 3 -- so the %DO loop would iterate 3 times.

If this is related to a stored process, you might want to post this question in the stored process forum. If this is related to a SAS/IntrNet program or custom front end (part of the BI Platform), you might want to work with Tech Support.

cynthia
chang_y_chung_hotmail_com
Obsidian | Level 7

This macro assumes a so-called macro variable array. I am not a big fan, but sometimes you have no choice.I would have written the macro a bit differently, but the concept remains the same.

   %*-- returns a macro-quoted comma-separated double-quoted text,
      given an mac var array root1 - rootn, where root0 evaluates to n.
      if root0 does not exists then root should exists as this macro
      returns its value enquoted --*;
   %macro qCsqv(root=);
      %if not %symexist(&root.0) %then %do;
         %*;%qsysfunc(quote(&&&root))
         %return;
      %end;
      %local i;
      %do i = 1 %to &&&root.0;
         %if &i > 1 %then %*;%str(, );
         %*;%qsysfunc(quote(&&&root.&i))
      %end;
   %mend  qCsqv;

   %*-- test1. when p0 exists --*;
   %let p0 = 3;
   %let p1 = a;
   %let p2 = b;
   %let p3 = c;
   %put %qCsqv(root=p);
   %*-- on log
   "a", "b", "c"
   --*;

   %*-- test2. when p0 does not exist --*;
   %symdel p0 p1 p2 p3;
   %let p = hello;
   %put %qCsqv(root=p);
   %*-- on log
   "hello"
   --*;

saspert
Pyrite | Level 9
Thank you Cynthia for your diagnosis.
Also, thank you Chang for your alternative method. I think your method worked better.

The macro call that I posted gave this in the log
MLOGIC(TEST): %PUT &old
SYMBOLGEN: Macro variable OLD resolves to "BOEING CORPORATION "
SYMBOLGEN: Some characters in the above value which were subject to macro quoting have been unquoted for printing.
"BOEING CORPORATION "

and Chang's code gave this in the log
MLOGIC(TEST): %PUT &new
SYMBOLGEN: Macro variable NEW resolves to "BOEING CORPORATION"
SYMBOLGEN: Some characters in the above value which were subject to macro quoting have been unquoted for printing.
"BOEING CORPORATION"

But, I still have a few questions.
1. I am thinking %str("&&&parm") resulted in the extra spaces. Do you know why?
I tried this to remove any extra spaces but it did not make a difference.
PROC SQL;
SELECT DISTINCT trim((DC.PRCHSR_NM)) AS PNAME
into :PNAME
FROM EHP.DC AS DC
WHERE DC.PRCHSR_CD = "BOI"
order by 1;
QUIT;

2. I am getting different results while running the same code in different places. Sometimes it returns "&PNAME in an EG session. When I run it in a stored process, it gives a blank output. Is this a question for Tech Support?
Cynthia_sas
SAS Super FREQ
Hi:
About #1:
Let's just ignore everything about the macro program you started with and go back to basics of how macro variables are created and look at what happens in the SQL step. Here's some sample code (shown in the SAS log):
[pre]
919 proc sql noprint;
920 SELECT DISTINCT trim(name) AS PNAME
921 into :PNAME
922 FROM sashelp.class AS DC
923 WHERE dc.name = "John";
924 QUIT;
NOTE: PROCEDURE SQL used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds


925
926 ** show trailing spaces for PNAME;
927 %put PNAME |&pname|;
PNAME |John |
928
929 ** %LET will remove trailing spaces;
930 %let pname=&pname;
931
932 ** show trailing spaces gone;
933 %put PNAME |&pname|;
PNAME |John|
[/pre]

The internally stored value for NAME ($8) is what gets written to the macro variable &PNAME. So even if TRIM briefly trims trailing blanks in memory during the SQL step, it is the internal value that is used. The first %PUT shows a | symbol on either side of the resolved value for &PNAME. The behavior is explained further in this Tech Support note:
http://support.sas.com/kb/2/748.html

A simple %LET will remove trailing spaces. (as explained in the note and shown in the above example).

An alternative to PROC SQL's INTO (for simple examples like your example) is to use DATA _NULL_ and CALL SYMPUT.
[pre]
942 data _null_;
943 set sashelp.class;
944 where name = "John";
945 call symput("DNAME",compress(name));
946 run;

NOTE: There were 1 observations read from the data set SASHELP.CLASS.
WHERE name='John';
NOTE: DATA statement used (Total process time):
real time 0.03 seconds
cpu time 0.01 seconds


947 %put DNAME |&dname|;
DNAME |John|
[/pre]

If you prefer the SQL approach, then a simple %LET will take care of trailing spaces.

#2: You say you are getting different results when running your code in different places. If this is a stored process and you are getting different results with the same stored process in different client applications, then you should work with Tech Support on this issue.

cynthia
saspert
Pyrite | Level 9
Thank you Cynthia for the tip on how macro variables store data.
I think I have to contact Tech Support on this.

Regards,
deleted_user
Not applicable
Hello,

Cynthia, I figured out that addingseparated by ' ' in proc sql also removes trailing blanks. of course, it makes not sense when you are selecting only one record but for removing trailing blanks.



Marius
Ksharp
Super User
Hi.
In proc sql ,selecting only one record (i.e. single macro variable) ,that macro variable will keep the trailing blanks.


Ksharp
Ksharp
Super User
Hi.
In proc sql ,selecting only one record (i.e. single macro variable) ,that macro variable will keep the trailing blanks.


Ksharp

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

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
  • 8 replies
  • 2092 views
  • 0 likes
  • 5 in conversation