SAS current date/timestamp - sas

I am trying to get insert the timestamp, current date and current time into a table using macro, but values are not getting displayed as expected. Can someone help on this please?
Also i m trying to write the SQL return code and message, but it displayed nothing.
%MACRO INS;
data _NULL_;
call symput('currdatets',datetime());
call symput('currdate',today());
call symput('currtime',timepart(datetime()));
%put currdatets> &currdatets;
%put currdater--2> &currdate;
%put currtime---2> &currtime;
run;
proc sql;
CONNECT TO DB2
insert into table
(entrytime, rundate, runtime)
values
(&currdatets,&currdate,&currtime)
DISCONNECT FROM DB2;
QUIT;
%PUT &SQLXMSG;
%PUT &SQLXRC ;
%MEND;
WARNING: Apparent symbolic reference CURRDATETS not resolved.
currdatets> &currdatets
WARNING: Apparent symbolic reference CURRDATE not resolved.
currdater--2> &currdate
WARNING: Apparent symbolic reference CURRTIME not resolved.
currtime---2> &currtime
WARNING: Apparent symbolic reference SQLXMSG not resolved.
&SQLXMSG
WARNING: Apparent symbolic reference SQLXRC not resolved.
&SQLXRC

Your first three macro-variables are not resolved because you specified the %put statements before the end of the data _null_ step (i.e., before the run;). symput assigns values produced in a DATA step to macro variables during program execution.
Use symputx instead of symput. It does not change the result though, but
symput gives you a message on the log about the conversion, while symputx does not. Moreover, symputx takes the additional step of removing any leading blanks that were caused by the conversion.
As for the two SQL Pass-Through automatic macro-variables you will need to provide us with more information. I don't know if intended or not, but you seem to use an explicit Pass-Through connection. If so, you might be missing information to connect to the server (e.g., connect to db2 (dsn= "xxxx")).
The automatic macro-variables SQLXRC and SQLXMSG are reset after each SQL Procedure Pass-Through Facility statement has been executed. If they are not resolved it means there were not any.
By the way, according to the documentation, you may want to use %SUPERQ() with SQLXMSG
SQLXMSG contains descriptive information and the DBMS-specific return
code for the error that is returned by the pass-through facility.
Note: Because the value of the SQLXMSG macro variable can contain
special characters (such as &, %, /, *, and ;), use the %SUPERQ macro
function when printing the following value: %put %superq(sqlxmsg);
%macro ins();
data _null_;
call symputx('currdatets',datetime());
call symputx('currdate',today());
call symputx('currtime',timepart(datetime()));
run;
%put currdatets> &currdatets. | currdate> &currdate. | currtime> &currtime.;
proc sql;
connect to db2;
insert into table (entrytime, rundate, runtime)
values (&currdatets,&currdate,&currtime);
disconnect from db2
;
quit;
%put %superq(sqlxmsg);
%put &sqlxrc. ;
%mend;
%ins();
currdatets> 1966238593.2 | currdate> 22757 | currtime> 33793.19107

Related

Macro resolution

I have a macro that resolves to a string which contains an ampersand and this cause the error WARNING: Apparent symbolic reference A not resolved.
For example
Data _NULL_;
T=%NRSTR("A&A");
call symput("test",T);
run;
%put &=test.;
Is there a way to only resolve only once? The NR function seems to remove the meaning of all & and prevent any resolutions. I only want it to be resolved once.
The following example works but I need it to be part of a data step as there are several other regex functions that are being used to create the A&Astring.
%let Test=%NRSTR(A&A);
%put &test;
Any ideas?
In the DATA step single quote the text value that is being sent to the macro environment.
To prevent the & from being interpreted as a resolution request, %superq the macro symbol when using it.
Data _NULL_;
T = 'A&A';
call symput("test",T);
run;
%put NOTE: test macro symbol value is %superq(test);
---------- LOG ----------
21 %put NOTE: test macro symbol value is %superq(test);
NOTE: test macro symbol value is A&A
To solve the problem with the first usage just use single quotes. This will allow you create the macro variable with the ampersand in it.
data _null_;
call symputx('test','A&A');
run;
Then use some macro code to add macro quoting. I find %SUPERQ() the easiest.
%let test=%superq(test);
If you are making a lot of macro variables in this way in the same data step you might want to use the RESOLVE() or CALL EXECUTE() function to allow you to run the %LET right after you create the macro variable.
data _null_;
set variable_list;
call symputx(name,value);
call execute(catx(' ','%let',name,'=%superq(',name,');'));
run;

How to mask an & in a SAS macro variable call via an indirect reference

I'm using the following macro code to generate a list of clients from a table:
%macro listclient;
proc sql noprint;
select unique(client)
into :cli1 -
from books; quit;
%put Total Number of Clients: &sqlobs..;
%do i=1 %to &sqlobs;
%put Client &i &&cli&i;
%end;
%mend listclient;
%listclient
My problem is that some of the clients have names such as Smith & Jones, so I need to use some sort of masking function to get a correct resolution. I've tried a few things, my best guess being to use %nrbquote(&&cli&i) but can't seem to null the problem out. I imagine that I am making a syntax error, or that there may be an issue with the indirect macro variable referencing.
The code runs but with a warning every time an & is encountered in the client name.
I would prefer not to go down the route of replacing all of the &s with "and"s and then changing them back again!
Can anybody be of assistance?
A useful macro function for this is %SUPERQ(). You just need to provide it with the name (not the value) of the macro variable to be quoted.
%do i=1 %to &sqlobs;
%put Client &i %superq(cli&i);
%end;
You could also build your macro variable to already be formatted as quoted strings. If you use single quotes then the macro triggers inside will be ignored.
proc sql noprint;
select distinct cats("'",tranwrd(name,"'","''"),"'")
into :name1 -
from sashelp.class
;
quit;
%put &=NAME1;
NAME1='Alfred'

Why does SAS warn that these variables have never been referenced

I am running a SAS Script that used to work.
When I run this part of the script
data PosteriorProbabilities (keep=Site VarStrg2(_,&MinGrp,&MaxGrp));
set TestOut;
run;
I get the following warning
WARNING: The variable _1 in the DROP, KEEP, or RENAME list has never
been referenced.
The macro for VarStrg2 is below.
%macro VarStrg2(Pref,V_Beg,V_End) ;
%do n = &V_Beg %to &V_End ; &Pref&n %end ;
%mend VarStrg2 ;
I need this step to work so that the rest of the program can run. Any help or suggestions would be most welcome.
The warning means that the variable _1 does not exist on the input data set.
I also assume you mean:
data PosteriorProbabilities (keep=Site %VarStrg2(_,&MinGrp,&MaxGrp));
set TestOut;
run;
With the % in front of VarStrg2(...).

SAS: How to assign the output value of a function-like macro?

I am very new using SAS and Im having hard time trying to assign the output value of a function-like macro to a macro variable. After testing, I have check that the value is computed correctly, but once I tried to assign it the program crashes. here you can find the code
%MACRO TP_BULLET(ZCURVE,TAU,YF=1);
/* KEEP ONLY THE ZERO CURVE UNTIL MATURITY*/
DATA _TEMP;
SET &ZCURVE;
IF MATURITY > &TAU THEN DELETE;
RUN;
PROC SQL NOPRINT;
SELECT DISTINCT 1- DF
INTO :NUME
FROM _TEMP
GROUP BY MATURITY
HAVING MATURITY = MAX(MATURITY);
QUIT;
PROC SQL NOPRINT;
SELECT SUM(DF)
INTO :DENO
FROM _TEMP;
QUIT;
PROC DELETE DATA=_TEMP;RUN;
%LET TP = %SYSEVALF(&YF*&NUME / &DENO);
&TP
%MEND TP_BULLET;
%MACRO TESTER2;
%LET K = %TP_BULLET(ZCURVE,TAU,YF=1);
%PUT .......&K;
%MEND TESTER2;
%TESTER2;
The error I am getting is the following
WARNING: Apparent symbolic reference DENO not resolved.
WARNING: Apparent symbolic reference NUME not resolved.
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:
1*&NUME / &DENO
So I suppose that the DATA Step is failing to create the sas table _TEMP, but I have no idea how to solve it. Thanks in advance for any help or sugestion
This is NOT a 'function like' macro - you are mixing SAS Macro language and Base SAS. Remember that the SAS Macro language is a code generator - and you are generating code, which is currently something like:
%let K=data _temp; set ZCURVE; ....
note how the above is not what you wanted to assign to the macro variable K.
To help with this, try running your macro with options mprint - this will show you the code being generated by your macro.
If you want your macro to act like a function, then (at a minimum) you should find NO code being generated via the mprint option..
All philosophical issues aside, you could add a parameter to your macro that specifies the new macrovariable (mv) that you want to create. So instead of
%Let k = %TP_BULLET(ZCURVE,TAU,YF=1);
you could call
%TP_BULLET(ZCURVE,TAU,mvOutput=k,YF=1);;
Your macro would need to be modified slightly with
%MACRO TP_BULLET(ZCURVE,TAU,mvOutput,YF=1);
%GLOBAL &mvOutput;
........ Same code as above .........
%Let &mvOutput = &TP; *Instead of final line with '&TP';
%MEND;
It is not a very SAS-y way to accomplish it, but it can help keep things more modular and comprehensible if you're working with more programming backgrounds, rather than SAS.

Using a dynamic macro variable in a call symput statement

I posted a question a while back about trimming a macro variable down that I am using to download a CSV from Yahoo Finance that contains variable information on each pass to the site. The code that was suggested to me to achieve this was as follows:
data _null_;
a = "&testvar.";
call symputx('svar',trim(input(a,$8.)));
run;
That worked great, however I have since needed to redesign the code so that I am declaring multiple macro variables and submitting multiple ones at the same time.
To declare multiple macros at the same time I have used the following lines of code:
%let svar&e. = &svar.;
%put stock_ticker = &&svar&e.;
The varible &e. is an iterative variable that goes up by one everytime. This declares what looks to be an identical macro to the one called &svar. everytime they are put into the log, however the new dynamic macro is now throwing up the original warning message of:
WARNING: The quoted string currently being processed has become more than 262 characters long. You
may have unbalanced quotation marks.
That i was getting before i started using the symputx option suggested in my original problem.
The full code for this particular nested macro is listed below:
%macro symbol_var;
/*here the start row and end row created in the macro above are passed to this nested macro and then passed through the*/
/*source dataset. at the end of the loop each ticker macro variable is defined in turn for use in the following nested*/
/*macro, symbol by metric.*/
%do e = &beg_point. %to &end_point. %by 1;
%put stock row in dataset nasdaq ticker = &e.;
%global svar&e;
proc sql noprint;
select symbol
into :testvar
from nasdaq_ticker
where monotonic() = &e.;
quit;
/*convert value to string here*/
data _null_;
a = "&testvar.";
call symputx('svar',trim(input(a,$8.)));
run;
%let svar&e. = &svar.;
%put stock_ticker = &&svar&e.;
%end;
%mend;
%symbol_var;
Anyone have any suggestions how I could declare the macro &&svar&e. directly into the call synputx step? It currently throws up an error saying that the macro variable being created cannot contain any special characters. Ive tried using &QUOTE, %NRQUOTE and %NRBQUOTE but either I have used the function in an invalid context or I haven't got the syntax exactly right.
Thanks
Isn't this as simple as the following two line data step?
%macro symbol_var;
/*here the start row and end row created in the macro above are passed to this nested macro and then passed through the*/
/*source dataset. at the end of the loop each ticker macro variable is defined in turn for use in the following nested*/
/*macro, symbol by metric.*/
data _null_;
set nasdaq_ticker(firstobs=&beg_point. obs=&end_point.);
call symputx('svar' || strip(_n_), symbol);
run;
%mend;
%symbol_var;
Or the following (which includes debugging output)
%macro symbol_var;
/*here the start row and end row created in the macro above are passed to this nested macro and then passed through the*/
/*source dataset. at the end of the loop each ticker macro variable is defined in turn for use in the following nested*/
/*macro, symbol by metric.*/
data _null_;
set nasdaq_ticker(firstobs=&beg_point. obs=&end_point.);
length varname $ 32;
varname = 'svar' || strip(_n_);
call symputx(varname, symbol);
put varname '= ' symbol;
run;
%mend;
%symbol_var;
When manipulating macro variables and desiring bullet-proof code I often find myself reverting to using a data null step. The original post included the problem about a quoted string warning. This happens because the SAS macro parser does not hide the value of your macro variables from the syntax scanner. This means that your data (stored in macro vars) can create syntax errors in your program because SAS attempts to interpret it as code (shudder!). It really makes the hair on the back of my neck stand up to risk my program at the hands of what might be in the data. Using the data step and functions protects you from this completely. You will note that my code never uses an ampersand character other than the observation window points. This makes my code bullet proof regarding what dirty data there may be in the nasdaq_ticker data set.
Also, it is important to point out that both Dom and I wrote code that makes one pass over the nasdaq_ticker data set. Not to bash the original posted code, but looping in that way causes a proc sql invocation for every observation in the result set. This will create very poor performance for large result sets. I recommend developing an awareness of how many times a macro loop is going to cause you to read a data set. I have been bitten by this many times in my own code.
Try
call symputx("svar&e",trim(input(a,$8.)));
You need double quotes ("") to resolve the e macro.
As an aside, I am not sure you need the input statement if $testvar is a string and not a number.
I would have written this as
%macro whatever();
proc sql noprint;
select count(*)
into :n
from nasdaq_ticker;
select strip(symbol)
into :svar1 - :svar%left(&n)
from nasdaq_ticker;
quit;
%do i=1 %to &n;
%put stock_ticker = &&svar&i;
%end;
%mend;