BookmarkSubscribeRSS Feed
rbm
Calcite | Level 5 rbm
Calcite | Level 5
I'm trying to use, within a data step, a macro variable that was created within the same data step using symput function but I'm getting an error message. I would like to know if there is any function that I could use for that purpose or if there is any way to get around this limitation. Please see below the code and the error message.

%macro test;

data &_output;
%global scr;
set &_input;
call symput('scr', scr_def);
%do i = 5 %to 1 %by -1;
%let k = %eval(&i + &scr);
%end;
run;

%mend;
%test;

ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required.
10 REPLIES 10
RickM
Fluorite | Level 6
From the online documentation:


Because %EVAL does not convert a value containing a period to a number, the operands are evaluated as character operands. When %EVAL encounters a value containing a period, it displays an error message about finding a character operand where a numeric operand is required.

try converting to numeric with the input function. Message was edited by: RickM
rbm
Calcite | Level 5 rbm
Calcite | Level 5
I tried with input(&scr,8.) and symget('scr') but none of them worked
RickM
Fluorite | Level 6
try sysevalf() if the data has decimals
sbb
Lapis Lazuli | Level 10 sbb
Lapis Lazuli | Level 10
You are attempting to mix SAS macro language elements with DATA step elements. Also, what purpose does the macro variable K have? You set a value and then do not reference it in the code snippet revealed in your post.

For what it's worth, the RUN; statement is key here - because SAS must compile the DATA step before you will get the CALL SYMPUT executed. And, so, without the macro variable set, you will not be able to execute your %DO logic.

Suggest you increase/improve your SAS-generated diagnostic output by adding the statement below:

OPTIONS SOURCE SOURCE2 MGEN SGEN MPRINT;

...and possibly needing...

OPTIONS MLOGIC;

Scott Barry
SBBWorks, Inc.

Recommended Google advanced search arguments for this topic/post:

data step macro variable run statement site:sas.com

scope macro variables site:sas.com

macro programming data step site:sas.com
rbm
Calcite | Level 5 rbm
Calcite | Level 5
I think that I had to give you more information about the final intention of my code. I need to create the macro variable K to be used as "index" for another macro variable that was previously created. Please see the code below.


%macro test;

data _null_;
set &_nie_lkp;
call symput('_nie'||left(_n_), nie_avg);
run;

data &_output;
%global scr;
set &_input;
call symput('scr', scr_def);
%do i = 5 %to 1 %by -1;
%let k = %eval(&i + &scr);
%put &&_nie&k;
%end;
run;

%mend;
%test;
sbb
Lapis Lazuli | Level 10 sbb
Lapis Lazuli | Level 10
Okay - for whatever reason you are generating macro variable displays with %PUT statements to the SAS log.

The current position of the RUN; statement will not work, as I stated before. The DATA step must compile and execute successfully to get your macro variable "scr" generated -- so it can be available (after the DATA step completes) to reference within your %DO / %END logic.

Also, you may want to use one of the MACRO language diagnostic statements below to ensure that your DATA step logic is generating what you expected in the first DATA step:

%put _local_;

.or.

%put _global_;

.or.

%put _all_;

I encourage you to peruse and review the recommended SAS support website references.

Scott Barry
SBBWorks, Inc.
Cynthia_sas
SAS Super FREQ
Ah, I see. You seem to want to create macro variables in one DATA step program and then you want to do a lookup (from those macro variables) in a second data step program -- based on some value from data in the second data step program.

I'm still not convinced you need a macro %DO loop yet. Consider the following macro program, %PUT_GET.

First, I make 38 macro variables &_NIE1-&_NIE19 and &_AGE1-&_AGE19 -- from the names and ages in SASHELP.CLASS. Next, I have a macro %DO loop write those values to the SAS log. Finally, in a subsequent DATA step in the macro program, I show 3 approaches:
1) Use SYMGET to get the values out of the macro lookup table
2) Use math to get successive values out of the macro lookup table into hardcoded variable names (still with SYMGET)
3) Finally, use 2 ARRAYs inside a DATA step DO loop to make 19 dataset variables to hold name and make 19 dataset variable to hold age (the ARRAY variables are also assigned values with SYMGET.

Each of these approaches uses data in SASHELP.SHOES. Basically, using the STORES variable as an "index" to get some or all of the macro variable values from the macro symbol table. (STORES is just an arbitrary numeric variable that represents the number of stores for an observation in SASHELP.SHOES).

Note how SYMGET can use a DATA step/data set variable as the "index" to retrieve a macro variable value from the macro symbol table. I don't see where your lookup needs a macro %DO loop yet.

This is an older paper that talks about using SYMPUT and SYMGET for lookups: http://www2.sas.com/proceedings/sugi25/25/cc/25p078.pdf and here's a paper specifically on lookup techniques (not limited to macro techniques):
http://www2.sas.com/proceedings/sugi27/p011-27.pdf
http://www.lexjansen.com/sugi/sugi21/is/127-21.pdf

cynthia

[pre]
%macro put_get;

** First, make macro variables from sashelp.class;
data _null_;
set sashelp.class;
call symput('_nie'||left(put(_n_,2.0)), name);
call symput('_age'||left(put(_n_,2.0)), put(age,2.0));
run;

** Next macro DO loop -- look in log for this output -- what values are in the macro variables?;
%do i = 1 %to 19;
%put i = &i;
%put _nie&i val is &&_nie&i ;
%put _age&i val is &&_age&i ;
%put **** **** **** **** ****;
%end;

** now, arbitrarily use the STORES value from sashelp.shoes;
** to retrieve a value from the macro symbol table;
** using the SYMGET function;
data shoeclass;
set sashelp.shoes;

** stores is a variable whose value can range from;
** 1 to 41 -- since sashelp.class only has 19 obs, we will just;
** use obs with that many stores or less from a few regions. STORES will now be;
** what we use for lookup from the macro symbol table.;
if stores le 19 and
region in ('Canada', 'Pacific');

** Approach 1: lookup only based on stores directly with values assigned into a few variables;
lookup1 = symget('_nie'||left(put(stores,2.0)));
lookup2 = symget('_age'||left(put(stores,2.0)));

** Approach 2: hard-code numbered variables and use math in the SYMGET function;
** to get 2 sets of successive values.;
if stores le 18 then do;
lkup_nm1 = symget('_nie'||left(put(stores,2.0)));
lkup_ag1 = symget('_age'||left(put(stores,2.0)));
lkup_nm2 = symget('_nie'||left(put(stores+1,2.0)));
lkup_ag2 = symget('_age'||left(put(stores+1,2.0)));
end;

** Approach 3: Use an Array and a DATA step DO loop and fill the array;
** using SYMGET -- define array size as max number of possible lookups -- 19;
array nm $8 nm1-nm19;
array ag ag1-ag19;
** now use a data step DO loop;
do ind = stores to 19;
nm(ind) = symget('_nie'||left(put(ind,2.0)));
hold =symget('_age'||left(put(ind,2.0)));
ag(ind) = input(hold,2.0);
end;

run;
%mend put_get;

** Invoke the Macro;
%put_get;

** Examine the output created in the program above;
ods listing close;
ods html file='lookup_macro.html' style=sasweb;
proc report data=work.shoeclass nowd;
title 'Output from all 3 Lookup Approaches';
column region sales stores
('Approach 1' lookup1 lookup2)
('Approach 2' lkup_nm1 lkup_ag1 lkup_nm2 lkup_ag2 )
('Approach 3' nm1 ag1 nm2 ag2 nm3 ag3 nm4 ag4 nm5 ag5 nm6 ag6 nm7 ag7 nm8 ag8
nm9 ag9 nm10 ag10 nm11 ag11 nm12 ag12 nm13 ag13
nm14 ag14 nm15 ag15 nm16 ag16 nm17 ag17 nm18 ag18 nm19 ag19);
run;
ods html close;
title;
[/pre]
rbm
Calcite | Level 5 rbm
Calcite | Level 5
By using the combination symget&put functions, as you suggested me to do, I was able to solve the problem. Thanks a lot Cynthia and everyone who tried to help me.

Here is the final version of the code:

%macro expected_future_profit(_input =,
_baseline_def =,
_baseline_attr_h =,
_baseline_attr_s =,
_nie_lkp =,
_nir_lkp =,
_losses_lkp =,
_rf =,
_output =);

* CREATE THE MACRO VARS FOR BASELINE FUNCTIONS;
data _null_;
set &_baseline_def end=no_more;
call symput('_base_def'||left(_n_), _surviv_);
if no_more then do;
call symput('count', _n_);
end;
run;

data _null_;
set &_baseline_attr_h;
call symput('_base_attr_h'||left(_n_), _surviv_);
run;

data _null_;
set &_baseline_attr_s;
call symput('_base_attr_s'||left(_n_), _surviv_);
run;

* CREATE THE MACRO VARS FOR REVENUE;
data _null_;
set &_nie_lkp;
call symput('_nie'||left(_n_), nie_avg);
run;

data _null_;
set &_nir_lkp;
call symput('_nir'||left(_n_), nir_avg);
run;


* CREATE THE MACRO VARS FOR LOSSES;
data _null_;
set &_losses_lkp;
call symput('_losses'||left(_n_), losses_avg);
run;

* EXPECTED FUTURE PROFITABILITY CALCULATION;
data &_output;
set &_input;
* RECURSIVE EQUATION;
%let count = &count;
vp = 0;
%do i = (&count-1) %to 10 %by -1;
%let iplus = %eval(&i + 1);
nie_val = symget('_nie'||left(put(&i + &count*scr_def_seg, 3.0)));
nir_val = symget('_nir'||left(put(&i + (&count*scr_def_seg), 3.0)));
losses_val = symget('_losses'||left(put(&i + (&count*scr_def_seg_roll), 3.0)));
vp = ((&&_base_attr_h&iplus/&&_base_attr_h&i)**exp(- scr_attr_h))*((&&_base_attr_s&iplus/&&_base_attr_s&i)**exp(- scr_attr_s))*
((((&&_base_def&iplus/&&_base_def&i)**exp(- scr_def))*(nir_val + nie_val + (vp/(1+&_rf))) +
(1 - (&&_base_def&iplus/&&_base_def&i)**exp(- scr_def ))*losses_val));
%end;
run;

%mend expected_future_profit;

%expected_future_profit(_input =intest,
_baseline_def = dat.baseline_def,
_baseline_attr_h = dat.baseline_attr_h,
_baseline_attr_s = dat.baseline_attr_s,
_nie_lkp = dat.nie_lkp,
_nir_lkp = dat.nir_lkp,
_losses_lkp = dat.losses_lkp,
_rf = 0,
_output = test);
sbb
Lapis Lazuli | Level 10 sbb
Lapis Lazuli | Level 10
Pretty convoluted (one person's opinion) -- never stated what you were attempting to accomplish in the beginning.

Appears you took observations on the input-side, went horizontal with creating macro variables, then back to vertical (observations) in the final DATA step.

Most likely what you have accomplished could have been done in fewer, simpler steps using SAS ARRAYs -- also we have not seen a working SAS log with "meaningful" and "correct" values rendered - have to take your word.

Scott Barry
SBBWorks, Inc.
Cynthia_sas
SAS Super FREQ
Hi:
You will have several other issues with this code.
1) You cannot use SYMPUT to create &SCR and then use &SCR in the same data step program.
2) Also, your %let for macro variable K is probably not going to work as you intend...aside from the issue of &SCR not being available... generally, a %LET statement should not be used inside a data step program.

Generally, you use a %DO in a macro program because you want to generate multiple DATA step statements for execution -- imagine that you needed to generate 100 IF statements or 100 assignment statements and you didn't want to type them all.

You don't say what your end result is or why you think a macro %DO loop is needed. It may be that you do not need a macro %DO loop and just need a regular DO loop.

At any rate #1 and #2 are going to NOT work, as described here and in the macro documentation:
http://support.sas.com/kb/23/182.html
http://support.sas.com/kb/22/987.html
http://www2.sas.com/proceedings/forum2007/238-2007.pdf
http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/a001071826.htm
http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/a001072359.htm
http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/a001302436.htm#tw3514-time
http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/a001071862.htm
http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/a001071889.htm


And, this SUGI paper is particularly helpful if you are new to macro processing concepts:
http://www2.sas.com/proceedings/sugi28/056-28.pdf

cynthia

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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
  • 10 replies
  • 1781 views
  • 0 likes
  • 4 in conversation