BookmarkSubscribeRSS Feed
FrankB
Fluorite | Level 6

I'm trying to use a variable during optimization as an input argument for a macro statement. But when I try the following code I get these error messages:

 

"ERROR: Undeclared array referenced: Term_Rate.
ERROR: Variable Term_Rate has not been declared as an array.".

 

However I can see the values of the variable if I use a print function in the macro statement. I appreciate if someone can help me to solve the issue.

 

data Rate;
input Product_Term $6. Term_Rate 5.;
datalines;
A 3.1
B 3.2
C 3.3
D 3.4
E 3.5
F 3.6
;

 

proc optmodel;
set<string> Product_Terms;
NUM Term_Rate {p in Product_Terms};
read data Rate into Product_Terms=[Product_Term] Term_Rate ;
%Profit(price=Term_Rate);
quit;

 

 

%Macro profit(price=);

%let full_output = (&price['A'] );

print &full_output.;  /* the results are printed here without any problem*/

data step;
set Rate;
if Product_Term='A' then Term_Rate=(&full_output. +4); /*I get the error message here*/
run;
%Mend profit;

7 REPLIES 7
ballardw
Super User

The way you define full_output = (&price['A'] );

 

This line of code

if Product_Term='A' then Term_Rate=(&full_output. +4)

looks like this after the macro processor works with it:

if Product_Term='A' then Term_Rate=((&price['A'] ) +4)

you do not show what value you used for the macro parameter &price but if it was TERM_RATE

then the above line becomes

if Product_Term='A' then Term_Rate=((Term_Rate['A'] ) +4)

And is treating Term_rate as an array because anything that looks like a variable followed by [], {} or () is assumed to be an array as is the only construct that variables can have with those characters.

 

Use

Options mprint symbolgen;

rerun the macro and look at the log see what your macro is generating.

 

 

FrankB
Fluorite | Level 6

Thanks for the response. Do you know how to use arrays in data step as a single value variable?

ballardw
Super User

Before you use an array you have to declare it with an array statement. The array statement determines the contents as in the number of elements, whether they are numeric or character contents and what the array indices look like (1 to 10, 50 to 123 or what ever).

An array may NOT be the same as an existing variable.

You could declare an array with a single element as:

 

data junk;
   array v {1};
   v[1]=10;
   y = 1.2;
   put v[y];
run;

 

Which would assume the array is numeric and create a variable name V1 to hold the value in.

SAS also supports temporary arrays if need the values but do not want to keep variables around.

It would depend on exactly what you are attempting to do.

 

Also last I checked SAS doesn't really like the index of an array to be a character value. The index may be an expression that yields a numeric result such as the name of a datastep variable or a calculation (decimals ignored and negative values very problematic).

FrankB
Fluorite | Level 6

I think the problem I have is with the communication between the optimizer variable and macro statement. Suppose I change the code as the following:

 

data Rate;
input A B ;
datalines;
3.1 3.2
;

 

data Rate2;
input Product_Term $6. Term_Rate 5.;
datalines;
A 3.1
B 3.2
C 3.3
;

 

 

proc optmodel;
VAR A, B ;
read data Rate into A B ;

%Profit(price=A);
quit;

 

%Macro profit(price=);

print (&price+1); /*again this shows the correct value*/

 

data step;

set Rate2;
if Product_Term='A:V5YC' then Term_Rate=(&price+1 );
run;
%Mend profit;

 

So the outcome of this process will be the following table:

Product_TermTerm_RateA
A  
B3.2 
C3.3 

 

 

But it is not clear why a seperate column named "A" is created and why the Term_Rate in the first row is empty instead of 4.1?

ballardw
Super User

One of the key bits when working with macros is having plain non-macro code that works before attempting to implement a macro.

 

If you did not have a macro what would the entire code you are attempting look like?

 

An occasional consideration with macros is also providing explicit data step and proc boundaries in the form of Run; or Quit; as appropriate for procedures.

 

You are likely getting a variable A with all missing values as you have created a DATA step using this code:

data step;
   set Rate2;
   if Product_Term='A:V5YC' then Term_Rate=(A +1 );
run;

Since dataset Rate2 does not have a variable A then SAS creates it and assigns a missing value.

 

Since Product_term only has one character to match against the value A:V5YC it is true (but not actually equal) Term_Rate is assigned the value of ( . + 1) which is missing.

FrankB
Fluorite | Level 6

Thanks for the response.

 

It should be noted that the macro statement works fine if I use a constant numeric value as the input argument but the problem is with sending a variable as the input and use it's values inside the macro statement.

 

Can you clarify why the print (&price +1) runs without any problem and adds 1 to the value of A which is 3.1 but the Term_Rate=(&price +1) considers &price as a letter A instead of the numeric value? And how can I use the value of the variable A in the data step instead of the variable name?

ballardw
Super User

As I mentioned I can't run code with Proc Optmodel so there's issues there.

But maybe you want to really look at your example data set Rate2. As constructed in your example code Term_rate is missing and Product term has values like "A 3.1".

See if this changes the results any:

 

data Rate2;
   informat Product_Term $6. Term_Rate 5.;
   input Product_Term  Term_Rate ;
datalines;
A 3.1
B 3.2
C 3.3
;
run;

Some

 

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
  • 7 replies
  • 15490 views
  • 2 likes
  • 2 in conversation