SAS: Apparent symbolic reference not resolved for Macro reference - sas

I have understood, and seen in other programs, that the following syntax is true.
%let variable = 'something';
statement name "&variable\othertext"; // something\othertext
However, in the code I have written I get this error message: Apparent symbolic reference not resolved. for the line LIBNAME REMOTE
%let month = 'JUN';
%let year = '18';
%let zos = ***********
signon zos ********************;
libname name "*********************************";
rsubmit;
libname remote "AAAA.BBBB.&month&year.SASLIB" access = readonly;
proc download inlib=remote outlib=name;
run;
libname remote clear;
endrsubmit;
signoff;
What am I missing?

The MONTH and YEAR macro variables are being defined in your local session, yet you're trying to resolve them in a remote session.
Use %SYSRPUT and %SYSLPUT to assign macro variables between sessions.
/* Local to remote */
%LET MONTH = 12 ;
%LET YEAR = 2018 ;
%SYSLPUT MONTH = &MONTH ;
%SYSLPUT YEAR = &YEAR ;
rsubmit ;
%PUT &MONTH &YEAR ;
/* resolves 12 and 2018 respectively */
/* remote to local */
%SYSRPUT FOO = BAR ;
endrsubmit ;
%PUT &FOO ; /* resolves to BAR */

More context would help, but most likely you are not understanding the role that period plays in resolving macro variable (symbol) references. To allow you to place letters and digits next to macro variable references SAS needs a way to tell where the name of the macro ends and the plain text starts. Period is used for that.
So if you wanted to generate this string
"AAAA.BBBB.JAN18.SASLIB"
from month and year values. First make sure to set the macro variables to the text you actually want. Quotes are just text to the macro processor.
%let month=JAN ;
%let year= 18;
Then in when you replace the values with macro variable references you will need an extra period after &YEAR so that one actually is generated. You should probably just get in the habit of always adding the period when referencing a macro variable.
"AAAA.BBBB.&month.&year..SASLIB"

Related

Setting table value to macro variable SAS

I need to store a value from a table into a variable. I've tried let, symputx, and select into. In the current version I try to use symputx, but the variable is not being updated. The products table contains type, price_floor, price_tier1, price_tier2.
%global price1;
%global price2;
%macro container();
DATA _null_;
SET products;
IF type = "Single" THEN DO;
CALL SYMPUTX('price1', price_floor,'g');
END;
IF type = "Multi" THEN DO;
CALL SYMPUTX('price1', price_tier1,'g');
CALL SYMPUTX('price2', price_tier2,'g');
END;
%PUT &=price1;
%PUT &=price2;
%mend;
Both price1 and price2 are null.
SYMBOLGEN: MACRO variable PRICE1 resolves to PRICE1=
SYMBOLGEN: MACRO variable PRICE2 resolves to PRICE2=
You don't have a run statement on your datastep, so your %put statement is being written to the log before the data step executes - so, the variables don't exist yet. It won't be run until you do provide a run statement or step boundary, or SAS might do that politely for you when the program is finished, but either way it's not being run before the %put.
Usually, this kind of program is an anti-pattern in SAS; you don't provide sufficient context, so maybe it's okay, but this will only work if you have only one row in the dataset - otherwise it probably won't do anything useful. The key word that's triggering me to write this is that you called this a "variable" - not a "macro variable" - in your question; SAS macro variables are not really "variables" and not meant to be used like a C variable or Python variable.
FYI to anyone interest, I decided to restructure the program as a whole. The original plan was to pass elements of a user defined array into %container, then use the assigned macro variables price1 and price2 as parameter in another macro call.
Instead of imbedding this data step in a macro, I created a table to contain all of the inputs I planned to pass into %container. Then I just used executes with the table variables concatenated within instead of direct macro calls.
data _null_;
SET products;
IF type = "Single" THEN DO;
CALL execute('%split_prod('||price_floor||');');
END;
IF type = "Multi" THEN DO;
CALL execute('%select_prod('||price1||','||price2||');');
END;
run;
There isn't anything wrong with the code besides the RUN.
%global price1;
%global price2;
data products;
infile cards dlm=',';
input Type $ price_floor price_tier1 price_tier2;
cards;
Multi, 40, 20, 60
;;;;;
%macro container();
DATA _null_;
SET products;
IF type = "Single" THEN DO;
CALL SYMPUTX('price1', price_floor,'g');
END;
IF type = "Multi" THEN DO;
CALL SYMPUTX('price1', price_tier1,'g');
CALL SYMPUTX('price2', price_tier2,'g');
END;
RUN;
%mend;
%container();
%PUT &=price1;
%PUT &=price2;
LOG:
96 %PUT &=price1;
PRICE1=20
97 %PUT &=price2;
PRICE2=60
You never showed your call for %container() so not sure what the underlying issue is, but CALL EXECUTE is a better method as debugging macros is painful.

SAS - Creating macro variables with a 'select into' which consists of other macro variables

Can someone please help me.
I have the code below. It does not generate an error but at the same time does not achieve what I want it to.
The intention is to create macro variables for each cell across a number of columns using a 'Select into'. I think the problem is the fact that the 'Select into' contains macro variables too.
%macro ld_macrovar;
proc sql noprint;
select count(portfolio)
into :a
from split_D;
%do i=1 %to &max_comb.; /*already defined elsewhere -actual value=2 */
select _&i.LGD
into :_&i.LGD1 - :_&i.LGD%left(&a)
from split_D;
%end;
quit;
%mend;
%ld_macrovar;
Thanks
Your macro variables are being assigned to the local scope of the macro. So if you want to access them outside the macro you will have to manually assign them to the global scope. This can be achieved by using the %global statement. Alternatively you can perform the processing that requires the macro variables inside the macro.
You can check the scope of your variables by running %put _ALL_; or %put _USER_.
%macro ld_macrovar(max_comb);
proc sql noprint;
select count(*) into :rows
from split_D;
quit;
%do i = 1 %to &max_comb.;
%do j = 1 %to &rows.;
%global _&i.LGD&j.;
%end;
%end;
proc sql noprint;
%do i = 1 %to &max_comb.;
select _&i.LGD
into :_&i.LGD1 -
from split_D;
%end;
quit;
%mend;
/* Dummy data */
data split_D;
do i = 1 to 10;
_1LGD = i**2;
_2LGD = exp(i);
output;
end;
run;
%ld_macrovar(2);
/* Print out all the user defined macro variables */
%put _USER_;
You can also avoid the need to use %left with &a by adding the trimmed option to your fist into statement (in SAS 9.3 and later or separated by "" in other versions).
A word of caution: If you are planning to use the values for further analysis or there are a lot of rows there ma be a better way to achieve what you want. Macro variables store only text and when the values are stored some precision may be lost. In general it's best to use data sets for moving/manipulating data and macro variables for when you need to parametrise your code.

Calling a macro variable from libname

How do I call a macro variable in the from clause of proc sql if I wish to use it in a libname?
Let me show you what I mean:
options nofmterr;
libname FRST "/ecm/retail/mortgage/nbk6kra/LGD/data/frst_201312bkts";
libname HELN "/ecm/retail/mortgage/nbk6kra/LGD/data/heln_201312bkts";
libname HELC "/ecm/retail/mortgage/nbk6kra/LGD/data/helc_201312bkts";
%let pathLGD = /new/mortgage/2014Q4/LGD;
%let prod = FRST;
/**************** Segment calculation **************** Date filter to be consistent with model documentation for segmented tables****************/
%macro Performance(prod);
proc sql;
create table lgd_seg_&prod as
select distinct
SegDT_LGD_2013,
min(ScoreDT_LGD_2013) as min_range,
max(ScoreDT_LGD_2013) as max_range,
count(*) as count,
mean(lgd_ncl_adjusted) as LGD_actual,
mean(ScorePIT_LGD_2013) as LGD_pred_pit_1,
mean(ScoreDT_LGD_2013) as LGD_pred_dt_1
from "&prod."scored;
where coh_asof_yyyymm > 200612
group by 1;
quit;
PROC EXPORT DATA=lgd_seg_&prod._fs
OUTFILE= "&pathLGD./lgd_seg.xlsx"
DBMS=XLSX REPLACE;
SHEET="&prod._lgd_seg_fs";
RUN;
%mend;
%Performance(prod=FRST);
%Performance(prod=HELN);
%Performance(prod=HELC);
So in the "from" clause, the macro is supposed to read FRST.scored, HELN.scored, and HELC.scored respectively. Currently it cannot find the file, and if I were to remove the quotation marks, then it'd become "work.FRSTscored".
I hope I've made this clear. Any input and comment is appreciated.
When you want to follow the the resolved value of a macro variable with an immediate additional character you should escape the macro variable with a full stop (.). For example:
%let start = one;
%put &start.two;
%put &start..two;
%put &startend;
onetwo
one.two
WARNING: Apparent symbolic reference STARTEND not resolved.
So your code should read from &prod..scored;.
If you ever need to you can also delay the resolution of a macro variable with double ampersand (&&):
%let end = two;
%let onetwo = three;
%put &&one&end;
%put &&&start&end;
Three
Three
Or:
%let three = inception;
%put &&&&&&&start&end;
inception
Remove quotation marks applied outside the macro variable prod and use two dots after macro variable (one to signify end of macro variable name and second one to specify the table name after the libname reference.
from &prod..scored

Syslput, rsubmit & macro

I am trying to pass a local macro variable within a macro to a remote session as follows (this example assumes 'mynode has already been signed on to):
%macro mytest;
%do i = 1 %to 3;
%syslput mynewval = &i;
rsubmit mynode;
%let mynewval2 = &mynewval;
%put &mynewval2;
endrsubmit;
This looks like the correct syntax to me, however '&mynewval2' is resolving to blank when I attempt to print it to the log. Can anyone see what I am doing wrong?
Thanks
%end;
%mend;
%mytest;
The %let mynewval2 = &mynewval; is being run on the client and not the server. IE, the local macro processor is running the code. It doesn't know what &mynewval is -- you defined it with the remote system.
Try wrapping the code inside the RSUBMIT in a macro. I don't have SAS/CONNECT licensed so I cannot test.
rsubmit mynode;
%macro run_on_server();
%let mynewval2 = &mynewval;
%put &mynewval2;
%mend;
%run_on_server();
endrsubmit;

SAS - Can't get code to work when put into a macro (remote server)

I have a block of code that connects to a remote server, passes a few variables to it, and then queries data on the server and then manipulates it. This code works exactly as I would expect it, producing the data I need.
However, I need to run the code in a macro loop. This is where it all breaks down. I'm not sure what the issue is, but I suspect it is some sort of variable scope problem. I have tried to research doing this online, but cannot figure it out.
The problem occurs in the data xtemp2 block. When I try to run this, I get the following errors:
WARNING: Apparent symbolic reference INTERVAL_SECONDS not resolved.
ERROR 22-322: Syntax error, expecting one of the following: a name,
a quoted string, a numeric constant, a datetime constant,
a missing value, INPUT, PUT.
and
WARNING: Apparent symbolic reference START_TIME not resolved.
ERROR 22-322: Syntax error, expecting one of the following: a name,
a quoted string, a numeric constant, a datetime constant,
a missing value, INPUT, PUT.
Please also note that I sometimes get similar errors with rtime, iprice, oprice, and itime. Once again, this code works perfectly well when I run it by itself. Putting it into a macro with a loop seems to generate these problems, which makes me think I am not initializing these variables properly. I would really appreciate any insight and tips you could provide.
%macro getthedata(nrows,ystart,yend); *nrows is the number of rows in the text file;
%do i=1 %to &nrows;
%do m=&ystart %to &yend;
(...)
signon username=_prompt_;
%syslput VAR1 = &var1;
%syslput M = &m;
rsubmit;
libname abc'/data/sasdata'; *Thisis where the datasets are located;
%let start_time = '9:30:00't; * starting time;
%let interval_seconds =15*60; * interval is 15*60 seconds, 15min;
data all2009;
set sas.a_&M.01:;
by symbol date time;
where symbol = &VAR1 and time between '9:30:00't and '16:00:00't;
run;
data xtemp2;
set all2009;
by symbol date time;
format itime rtime time12.;
if first.symbol=1 or first.date=1 then do;
*Initialize time and price when new symbol or date starts;
rtime=time;
iprice=bid;
oprice=ofr;
itime=&start_time;
end;
if time >= itime then do; *Intervalreached;
output; *rtime and iprice hold the last observation values;
itime = itime +&interval_seconds;
do while(time >= itime); *need to fill in alltime intervals;
output;
itime = itime +&interval_seconds;
end;
end;
rtime=time;
iprice=bid;
oprice=ofr;
retain itime rtime iprice oprice; *Carry time and price valuesforward;
*keep symbol date itime iprice rtime;
run;
proc download data=all2009 out=local.all30 (keep=SYMBOL DATE PRICE SIZE itime);
run;
endrsubmit;
(...)
%end;
%end;
%mend getthedata;
Options MPRINT;
%getthedata(3,2007,2007)
SOLUTION (per Joe's Answer)
I was able to successfully create the interval_seconds and start_time variables using the %NRSTR solution Joe posted.
Here is the relevant modified code section:
(...)
signon username=_prompt_;
%syslput VAR1 = &var1;
%syslput M = &m;
rsubmit;
libname abc'/data/sasdata'; *Thisis where the datasets are located;
%nrstr(%%)let start_time = '9:30:00't; * CHANGED LINE;
%nrstr(%%)let interval_seconds =15*60; * CHANGED LINE;
data all2009;
set sas.a_&M.01:;
by symbol date time;
where symbol = &VAR1 and time between '9:30:00't and '16:00:00't;
run;
(...)
I can give you a functional solution, but I haven't figured out the whys yet.
Basically, the %let statements (and %put statements) are being ignored. They're not being passed down - in fact they're being executed on the local machine. See this:
%let var1="Region1";
signon;
libname uwork slibref=work server=unix;
data uwork.pricedata;
set sashelp.pricedata;
run;
%macro getthedata(nrows,ystart,yend); *nrows is the number of rows in the text file;
%do i=1 %to &nrows;
%do m=&ystart %to &yend;
signon;
%syslput VAR1 = &var1;
%syslput ystart=&ystart;
%syslput yend=&yend;
%syslput start_time='01JAN1998'd;
%syslput interval_seconds=30;
rsubmit;
%*libname abc '/data/sasdata'; *Thisis where the datasets are located;
%let start_time = '01JAN1998'd; * starting time; *these are ignored by the rsubmit - why?;
%let interval_seconds =30; * interval is 15*60 seconds, 15min;
%put &start_time &interval_seconds;
data all2009;
set work.pricedata;
by date;
where year(date) ge &ystart. and year(date) le &yend.;
run;
data xtemp2;
set all2009;
by date;
format itime rtime time12.;
if first.date=1 then do;
*Initialize time and price when new symbol or date starts;
rtime=date;
iprice=price;
oprice=cost;
itime=&start_time;
end;
if date >= itime then do; *Intervalreached;
output; *rtime and iprice hold the last observation values;
itime = itime +&interval_seconds;
do while(date >= itime); *need to fill in alltime intervals;
output;
itime = itime +&interval_seconds;
end;
end;
rtime=date;
iprice=price;
oprice=discount;
retain itime rtime iprice oprice; *Carry time and price valuesforward;
*keep symbol date itime iprice rtime;
run;
/*proc download data=all2009 out=local.all30 (keep=SYMBOL DATE PRICE SIZE itime);
run;
*/
endrsubmit;
%put &start_time &interval_seconds;
%end;
%end;
%mend getthedata;
Options MPRINT;
%getthedata(3,1998,1998)
Notice that the %put statement at the end, after the endrsubmit, actually works - even though it shouldn't (the macro variables shouldn't be defined on the local machine). There must be some issue with RSUBMITs inside of macros having macro variables, and there I have no real answers other than %SYSLPUTting it before you rsubmit (hence why my example works).
You could consider moving the RSUBMIT code to a remote batch program that you execute rather than RSUBMITting, perhaps, or even %include- maybe that would get around it (ie, inside the RSUBMIT have an %include that is referring to a remote program).
Take a look at this SAS article, which gives you some explanation of what's happening (basically what I said is in fact the case) and how to work around it. SYSLPUT is the first suggestion, and using other workarounds like %NRSTR also are possibilities.
The code looks like it should run, but I've tried something similar and had same problem.
You create local macro so the macro statements like LET are executed locally. While datastep statements are executed by remote SAS.
The solution is to define macro in remote session.
See effect of where is macro compiled below:
1) local macro:
%macro local_macro;
rsubmit;
%put %sysget(COMPUTERNAME);
endrsubmit;
%mend;
%local_macro
2) remote macro
rsubmit;
%macro remote_macro;
%put %sysget(COMPUTERNAME);
%mend;
endrsubmit;
rsubmit;
%remote_macro
;
endrsubmit;