DATA Step, Macro, Functions and more

Using CALL SYMPUT in same datastep

Reply
Frequent Contributor
Posts: 75

Using CALL SYMPUT in same datastep

[pre]
data _null_;
call symput('yr', year(today() ) );

put "&yr.";
run;
[/pre]


[pre]
95 data _null_;
96 call symput('yr', year(today() ) );
97
98 put "&yr.";
WARNING: Apparent symbolic reference YR not resolved.
99 run;
[/pre]

Gday,

I was wondering why the above code returns an error the first time I run it? I suspect I'm not going to understand the reason (it resolves variables at program execution instead of macro execution).

How can I get around this, as I need to use the value from a variable in the same datastep as the macro variable is only relevant to the current record.


Thanks.

edit:

This is actually what I'm trying to run:

[pre]
%macro create_risk(section, ds, ccnt);

%macro se(c);
data _null_;
length tmp $200.;

tmp = "si_&c. = tmp_si;
rate_&c. = tmp_rate;
prem_&c. = tmp_prem;";

call symput('tmp2', tmp);
run;

data _null_;
put "horray &tmp2.";
run;
%mend;


data ns_risk_&section.;
set gins.risk_&ds. (obs = 2);

array si (&ccnt.) si01 - si&ccnt.;
array code (&ccnt.) code01 - code&ccnt.;
array pc (&ccnt.) PRINTCODE01 - PRINTCODE&ccnt.;
array r (&ccnt.) RATE01 - RATE&ccnt. ;
array p (&ccnt.) PREM01 - PREM&ccnt.;



*printcodes are usually 1 if present;
*for argis risk files they show up as 0;
do i = 1 to &ccnt.;
if pc ^= . then
do;
cc = substrn(code, 1, 4);

tmp_si = si;
tmp_rate = input(r, ?? best.);;
tmp_prem = p;;

call execute('%se(' || cc || ')' );

&tmp2.;
**%gg(cc );
end;
end;
run;
%put "yes2224" &tmp2.;
%mend;


%create_risk(FLST, fmlivstck, 05);
[/pre]

[pre]
RISK_Policy_binder_id RISK_FMLIVSTCK_id CHECKBOX01 CHECKBOX02 CHECKBOX03 CHECKBOX04 CHECKBOX05 CODE01 CODE02 CODE03 CODE04 CODE05 DESC01 DESC02 DESC03 DESC04 DESC05 DISCLOADPREM DISCORLOAD DISCORLOADCODE ISBLANKET ISINIT ISSIINIT ISXSINIT PREM01 PREM02 PREM03 PREM04 PREM05 RATE01 RATE02 RATE03 RATE04 RATE05 RISKSECDESCTEXT RISKSECGRP RISKSECGRPCODE SI01 SI02 SI03 SI04 SI05 STNDSI01 STNDSI02 STNDSI03 STNDSI04 STNDSI05 TERRPREM TERRRATE TOTPREM TOTPREMBEFADJ TOTPREMLESSTERR TOTSI XSAMT01 XSAMT02 XSAMT03 XSAMT04 XSAMT05 XSCODE01 XSCODE02 XSCODE03 XSCODE04 XSCODE05 XSDESC01 XSDESC02 XSDESC03 XSDESC04 XSDESC05 XSDESCTEXT01 XSDESCTEXT02 XSDESCTEXT03 XSDESCTEXT04 XSDESCTEXT05 XTRASI01 XTRASI02 XTRASI03 XTRASI04 XTRASI05 DISCLOADRATE PRINTSI01 PRINTSI02 PRINTSI03 PRINTSI04 PRINTSI05 PRINTCODE01 PRINTCODE02 PRINTCODE03 PRINTCODE04 PRINTCODE05 POLNO SITNO POLSEQ CONVSPARE
182021 14 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
188525 14 1 0 0 0 0 GRP101 Specified Livestock 0 . . 0 1 1 400 . . . . 0 Livestock Section 3818 FLSTFAL 5000 . . . . . . . . . . 400 400 400 5000 0 0 . . . STNDFAL ADDLFAL 4293 4294 . . . Standard Excess Additional Excess 5000 . . . . 0 $5,000 0 . . . . . .
[/pre]
^^
The first two records of my data source

Am not wanting a PROC TRANSPOSE solution...
Valued Guide
Posts: 2,175

Re: Using CALL SYMPUT in same datastep

I think you don't understand how call execute() works!
There is no way you can retrieve values generated by the execute-ed process in the step where call execute() appears. That is because call execute() "submits code" which only executes once the step with call execute() finishes.
However, I think you could achieve what you need with arrays for the values that your %CC macro was trying to fill si_1 - si_5, rate_1 - rate_5 and prem_1 - prem_5

At the same point, instead of [pre]call execute('%se(' || cc || ')' );[/pre] you would have code like[pre] array si_(&ccnt) ;
array rate_(&ccnt) ;
array prem_(&ccnt) ;
si_(i) = tmp_si;
rate_(i) = tmp_rate;
prem_(i) = tmp_prem;[/pre] but since you are already using similarly named arrays, I don't see why you decided to adopt call execute().

good luck
peterC
SAS Employee
Posts: 104

Re: Using CALL SYMPUT in same datastep

John,
Though the problems in the upper and lower code snippets are different, they are all based on the same timing issue - the maco processor processes at a different time than the data step. For example, let's start with a little demo code:
%let SCOPE=GLOBAL;
TITLE "&SCOPE macro variables before DATA _NULL_";
proc print data=sashelp.vmacro;
where SCOPE="&SCOPE";
run;

This produces a report:

OUTPUT window:
GLOBAL macro variables before DATA _NULL_

Obs scope name offset value
1 GLOBAL SCOPE 0 GLOBAL

Note that the macro variable yr does not yet exist. Now for your code:

data _null_;
call symput('yr', year(today() ) );
put "&yr.";
run;

When submitted the first time, the macro variable yr still does not exist so cannot be resolved before the DATA step is compiled. See the SAS log:
WARNING: Apparent symbolic reference YR not resolved.
10 run;
&yr.

Because the macro processor could not resolve the variable yr, the DATA step compiles with the value '&yr.' in the PUT statement.

Now, when the data step executed for the first time, it created and populated the macro variable yr. Run this code after the first DATA _NULL_ step to prove that this is true:

TITLE "&SCOPE macro variables after DATA _NULL_";
proc print data=sashelp.vmacro;
where SCOPE="&SCOPE";
run;

OUTPUT window:
Global macro variables before DATA _NULL_

Obs scope name offset value
1 GLOBAL SCOPE 0 GLOBAL
2 GLOBAL YR 0 2011


So the second time you run your DATA step, the variable yr already exists, and it will be resolved before the DATA step gets compiled. This will avoid the WARNING and replace the text &yr. in the PUT statement with 2011 as the data step compiles. This is why the second time you run the code, you get the expected results.

Hope this helps.
May the SAS be with you :-)
Frequent Contributor
Posts: 75

Re: Using CALL SYMPUT in same datastep

Thanks for the responses.

SASJedi, the first piece of code was an example of the problem I thought I had whcih I made up.

The later code is what I care about. Originally I didn't include it, but figured it would help me out more if I used my actual problem.

I am aware that the results of CALL SYMPUT cannot be used in the same datastep, this is documented and your example/demo kind of makes sense to me, however I still can't figure out why this feature is there.

Peter.C, it's true, I probably don't know how to use CALL EXECUTE properly, however I have used it based on examples I have seen in the past and managed to get what I wanted.

The reason why I was trying to use the CALL EXECUTE was because I want the variable to be called SI_GRP1 as opposed to SI_1. My issue is that the values in variable CODE01 for example isn't always the same, so if I just rename this to SI_1, it won't mean the same thing for the whole table.

I have that dud datastep because I thought it needed a buffer (RUN) or something to create the macro variables I was after. As pointed out if I can't use values genereated by CALL EXECUTE then this is clearly the wrong way of doing things. But, I'm not using values as such, I'm just creating a macro variable.

Does that make sense?
Super User
Posts: 9,676

Re: Using CALL SYMPUT in same datastep

call symput has only three type arguments.
variable name , text and text expression.
So you can try this:
1)call symput('yr', '2011' );

2)
year=year(today() );
call symput('yr', year );


Ksharp
Ask a Question
Discussion stats
  • 4 replies
  • 790 views
  • 0 likes
  • 4 in conversation