BookmarkSubscribeRSS Feed
DavidSmith2
Fluorite | Level 6

Anyone know a way to dynamically change a variable name in a symput statement? We need to communicate specific date ranges in a subsequent SQL statement and also an environment outside SAS Studio. The bolded 1 we wish to increment to 2, 3, etc. The upper boundary of the array V_From is unknown until data is read in.

 

Current code:

call symput("V_From1","'"||compress(put(V_From1,DATE9.))||"'d");

 

Full code:

data &LOCAL.CAMPAIGN_DATES_ARRAY(drop=Valid_From Valid_To x keep);
set &LOCAL.CAMPAIGN_DATES_UNIQUE nobs=nobs;
array V_From{&MAX_OBS} ; array V_To{&MAX_OBS};
retain;
do x = 1 to &MAX_OBS;
if _N_ = x then V_From{_N_} = Valid_From;
if _N_ = x then V_To{_N_} = Valid_To;
end;
if _n_ =nobs then keep=1;
if keep ne 1 then delete;
format V_From1-V_From6 date9.; /* UPDATE: SAS Does not support undefined array formatting */
format V_To1-V_To6 date9.; /* UPDATE: SAS Does not support undefined array formatting */

/* Had to manually do since dynamic wasn't working */
call symput("V_From1","'"||compress(put(V_From1,DATE9.))||"'d");
run;
%put &V_From1; run;

 

Thank you!

 

Screenshot 2024-02-22 145725.png

 

 

8 REPLIES 8
PaigeMiller
Diamond | Level 26

Where does macro variable &MAX_OBS get assigned a value?

 

This CALL SYMPUT where you want to dynamically assign a digit(s), is this done for each row of the input data set named &LOCAL.CAMPAIGN_DATES_UNIQUE? Or is this done for each column? Does the data have one row or many?

 

What is the screen capture you have provided, how does it relate to this problem, is it input data or desired output?

--
Paige Miller
DavidSmith2
Fluorite | Level 6

Thank you for replying. 

data _NULL_; /* Count rows for Array */
set &LOCAL.CAMPAIGN_DATES_UNIQUE nobs = N;
call symput('MAX_OBS',N);
run;
%put &MAX_OBS; run;

 

The screen print is the result of the existing code. Input looks like:

Screenshot 2024-02-22 151329.png

PaigeMiller
Diamond | Level 26

There are a number of questions that I asked which I don't see an answer to. It would be helpful to have answers to all my questions.

 

But I kind of get the feeling that diving into this mass of code, without more explanation, is going to be painful and fruitless. We need more explanation of what you are trying to do in the code, and we also need explanation of the overall purpose of the code (in words, not in code).

--
Paige Miller
DavidSmith2
Fluorite | Level 6
I understand. Thank you for your time. I'll package more appropriately and add on.

Regards,
Dave
ballardw
Super User

Call Symput and Call Symputx (which you should consider instead of Symput) take any string as the argument for the name of the macro variable to create so just use an approach to create the desired string.

 

And example similar to what I think you are requesting:

data _null_;
   set sashelp.class;
   
   call symputx(cats('Name',_n_),name);
run;

Creates macro variables Name1 through Name19, each with the value of a name from the SASHELP.Class data set.

 

So if you have an array index you  could use it similarly with the CATS (or other string function) to combine the value with a name stem.

 

If you are actually going to use those strings a dates for comparisons, calculations or manipulations you we be better off leaving them as integer values instead of bothering with the date literal string creation. Those really only belong where people need to see them.

DavidSmith2
Fluorite | Level 6
Thank you very much!
Tom
Super User Tom
Super User

The first argument to CALL SYMPUTX() (you should never use the ancient CALL SYMPUT() unless you really need to have leading or trailing spaces included in the macro variable's value) can be any character expression.

 

Normally you can just use the automatic variable _N_ (which increments on each iteration of the data step).

call symputx(cats('V_From',_n_),quote(put(V_From[_n_],DATE9.))||'d');

 

But your whole step seems way more complicated than it needs to be. And it has some confusing comments included to boot.

 

If you already know how many observations there are then the code to roll multiple observations of FROM and TO variables into a single observation with two sets of suffixed variables ("array") is just this simple step:

 

data &LOCAL.CAMPAIGN_DATES_ARRAY;
  set &LOCAL.CAMPAIGN_DATES_UNIQUE end=eof;
  retain V_From1-V_From&max_obs V_To1-V_To&max_obs ;
  format V_From1-V_From&max_obs V_To1-V_To&max_obs date9. ;

  array V_From [&MAX_OBS];
  array V_To [&MAX_OBS];

  V_From[_N_] = Valid_From;
  V_To[_N_] = Valid_To;
   
  if eof;
  drop Valid_From Valid_To ;
run;

If you want to generate a series of macro variables also then just add one or both of these lines before the  subsetting IF statement.

  call symputX(cats('V_From',_N_),quote(put(Valid_From,DATE9.))||'d');
  call symputX(cats('V_To',_N_),quote(put(Valid_To,DATE9.))||'d');

And if you haven't already made the MAX_OBS macro variable you can add this data step before the other to calculate it for you.

data _null_:
  call symputx('max_obs',nobs);
  stop;
  set &LOCAL.CAMPAIGN_DATES_UNIQUE nobs=nobs ;
run;

To see the count and the first and last V_FROM macro variable you could run this %PUT statement after the data step.

%put &=MAX_OBS &=V_From1 V_From&max_obs=&&V_From&max_obs;

And if the goal is just to make the macro variables and not the wide dataset then skip the data step completely and let PROC SQL make the macro variables for you.

proc sql noprint;
select quote(put(valid_from,date9.))||'d'
     , quote(put(valid_to,date9.))||'d'
  into :v_from1-
     , :v_to1-
from &LOCAL.CAMPAIGN_DATES_UNIQUE
;
%let max_obs=&sqlobs;
quit;

 

PS For most purposes just putting the actual integer number of days since 1960 into the macro variables is enough.  They will work just fine in most places where you would want to use a date value, since they are the values used to store the dates in question.

  call symputX(cats('V_From',_N_),Valid_From);
  call symputX(cats('V_To',_N_),Valid_To);

 

Patrick
Opal | Level 21

Based on your code you only want to process the last obs in your source table &LOCAL.CAMPAIGN_DATES_UNIQUE. If I understand the rest of your question correctly then code as below should do what you want.

data _null_;
  call symputx('last_obs',nobs);
  stop;
  set &LOCAL.CAMPAIGN_DATES_UNIQUE nobs=nobs;
run;

data _null_;
  set &LOCAL.CAMPAIGN_DATES_UNIQUE (firstobs=&last_obs);
  array arr_V_From{*} v_From:;
  array arr_V_To{*} v_To:;
  do i=1 to dim(arr_V_From);
    call symputx(cats('v_from_',i),arr_V_From[i] );
    call symputx(cats('v_to_',i)  ,arr_V_To[i]   );
  end;
run;

Above code also creates a macro variable &n_arr_elements that tells you how many macro variables have been created: &v_from_1 to &&v_from_1_&n_arr_elements.

Based on your description you want to use these macro variables somehow later on in a Proc SQL. If you explain and show us a bit more of your process then some improvements to your current design could be possible that would reduce complexity.

 

 

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
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
  • 8 replies
  • 633 views
  • 0 likes
  • 5 in conversation