Why does SAS warn that these variables have never been referenced - sas

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(...).

Related

What will be the output of this %macro function in SAS and how to display the output in sas studio

%macro segm1;
data _null_;
%do i=0 %to 8;
call symput("yyyymm_i",put(intnx('month',today(),-1,'b'),yymmn6.));
%end;
%mend;
%segm1;
run;
What will be the output and how to get/dispaly/view output of this macro code in sas studio?
Since a macro is used to generate SAS code to view the output of macro set the MPRINT option before running it. You will see that the macro generates a data statement and 8 call symput statements.
There are a lot of problems with that code.
Uses %DO loop where it should be using a DO loop.
Creates the same macro variable over and over.
Starts a data step, but does not end it. Was this on purpose? Why?
Creates LOCAL macro variables that will disappear when the macro finishes.
Uses older less functional call symput() function instead of call symputx().
If you want to create 8 macro variables just use a normal DO loop. No need for a macro. Use the value of the loop variable to change the name of the macro variable generated and the month the result represents.
data _null_;
do i=0 to 8;
call symputx(cats('yyyymm_',i),put(intnx('month',today(),-i,'b'),yymmn6.));
end;
run;
Which will create a series of macro variables named YYYYMM_0 to YYYYMM_8 with six digit strings like 202204 , 202203 , ... representing the current month back to eight months ago
If you did want to run that inside a macro and have the macro variables it creates available after the macro ends then set the optional third parameter to call symputx() to the string 'G' so that they are defined in the global symbol table instead of the local symbol table.
You can print individual macro variables to the log with the %put statement, like %put &yyyymm_i;
You can print all macro variable with %put _all_;, or if you are only interested in variables you created yourself: %put _user_; (or within a macro %put _local_;)
By the way, your code is wrong, try this
%macro segm1;
data _null_;
%do i=0 %to 8;
call symput("yyyymm_&i", put(intnx('month',today(),-1,'b'),yymmn6.));
%end;
%mend;
%segm1;
run;
%put _user_;

How to use a SAS Macro inside data step

I'm running a code similare to the following one and the data step is not working and I can't seem to understand why
%macro macro_1(variable);
rsubmit;
data want_&variable. (keep = a b c);
set have;
run;
endrsubmit;
%mend macro_1;
%macro testing;
%do i=1 %to 3;
%macro_1(&i.); /* My loop here*/
%end;
%mend testing;
%testing;
Here's the error I keep on getting :
Syntax error, expecting one of the following: a name, a quoted string, (, /, ;, DATA, LAST, NULL.
I have tried using the double ampersand or using more periods at the end, unsuccessfully however
Much thanks for any help !
You have defined the macro variable VARIABLE on the local machine, but the code that is using the macro variable is running on the remote machine. Try pushing the value to the remote machine before trying to use it.
%macro macro_1(variable);
%syslput variable=&variable;
rsubmit;
data want_&variable. (keep = a b c);
set have;
run;
endrsubmit;
%mend macro_1;

SYSERR Automatic Macro Variable

I have several programs in one SAS project, i.e program A -> program B ->.... I want to build dependency between programs using macro variables.
Program A will process few data step and procs. If ANY procedure in program A executes with errors, I would like to run program C. Otherwise run program B.
This seems to be tricky since syserr resets at each step boundary. If first data step in program A executes with error and the rest don't, then at the end of program A, syserr is still 0. I need macro variable value to be something other than 0 once error happens and the value can keep till program ends.
If the program dependency is based on other criteria (say values), the user-defined macro variables can handle that. For something related to system errors, I think SAS already has something can do the trick.But I can't find anything else except syserr, which doesn't seem to help.
Note: I find this SAS stop on first error. But basically it's to check the error status after each data step. That sounds crazy if program A contains 50+ data steps.
Easy - just use syscc!
SYSCC is a read/write automatic macro variable that enables you to
reset the job condition code and to recover from conditions that
prevent subsequent steps from running.
See documentation, but I guess you will be looking for something like:
%if &syscc > 4 %then %do;
%inc "/mypath/pgmB.sas";
%end;
%else %do;
%inc "/mypath/pgmA.sas";
%end;
The highest value of syscc is retained across step boundaries, always with an integer to represent the error level. Example values:
The values for SYSCC are:
0 is no errors no warnings
4 is warnings
greater than 4 means an error occurred
Note that there are some things it won't catch, but to improve it's effectiveness you can use:
options errorcheck=strict;
Finally - you mention 'sas project', if by this you mean you are using Enterprise Guide then please be aware of the advice in this usage note.
You could define a macro that kept track of the error status and run this after each step. The macro would look something like this:
%macro track_err;
%global err_status;
%let err_status = %sysfunc(max(&err_status, &syserr ne 0));
%mend;
Usage example below. First initialize the value to track the overall error status. The first datastep will fail, the second will run successfully and the final value of err_status will be 1.
%let err_status = 0;
data oops;
set sashelp.doesnt_exist;
run;
%track_err;
data yay;
set sashelp.class;
run;
%track_err;
%put &=err_status;
Final output:
ERR_STATUS=1
As far as 'sounding crazy to check the status after each step'... well SAS doesn't provide something for the exact requirement you have, so the only way to do it is literally to have something check after each step.
EDIT: Correction - looks like the syscc approach mentioned in RawFocus's answer actually shows there IS something that does this in SAS.
If you want the check to 'blend in' more with the code, then consider replacing your run and quit statements with a macro that performs the run/quit, then checks the status all in one. It will result in slightly cleaner code. Something like this:
%macro run_quit_track;
run;quit;
%global err_status;
%let err_status = %sysfunc(max(&err_status, &syserr ne 0));
%mend;
%let err_status = 0;
data oops;
set sashelp.doesnt_exist;
%run_quit_track;
data yay;
set sashelp.class;
%run_quit_track;
%put &=err_status;
Use one macro, call it runquitA. call this macro at the end of each proc sql or proc data in the place of quit; and run;
Example:
/*Program A*/
%macro runquitA;
; run; quit;
%if &syserr. ne 0 %then %do;
/*Call Program C*/
%end;
%mend runquitA;
proc sql;
create table class1 as
select * from sashelp.class;
%runquitA;
data class2;
set sashelp.class;
%runquitA;
/*Call Program B*/
/*end of Program A*/

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'

Using VTYPE on dataset with 0 observations

When using VTYPE on a dataset with 0 observations I do not get needed information.
Here is MWE:
Create simple set with 1 variable and 1 observation.
data fullset;
myvar=1;
run;
Create another set with same 1 variable and 0 observations.
data emptyset;
set fullset;
stop;
run;
Make a macro that opens set, checks vtype and prints it to log.
%macro mwe(inset);
%local TYPE;
data _NULL_;
set &inset.;
CALL SYMPUT("TYPE", VTYPE(myvar));
put TYPE;
stop;
run;
%put &=TYPE.;
%mend mwe;
When run on set with observations everything works fine:
%mwe(fullset);
TYPE=N
But when run with an empty set the TYPE does not get assigned
%mwe(emptyset);
TYPE=
I guess the reason is that no code lines are processed since the set has no observations. Is there any workaround for that?
NOTE:Using proc contents and parsing the result table is certainly an overkill for such a simple task
Your problem is not vtype(), but how the data step works with an empty dataset.
When the set statement attempts to pull a row and fails, the data step immediately terminates. This can be useful - for example, when you don't want it to do things after the last row in the dataset is past. But in this case, it is less useful. Your datastep terminates instantly upon the set statement, meaning your call symput never occurs.
However, you can take advantage of a different thing: the fact that SAS will happily create all of the metadata even before set, during compilation.
%macro mwe(inset);
%local TYPE;
data _NULL_;
CALL SYMPUT("TYPE", VTYPE(myvar));
set &inset.;
stop;
run;
%put &=TYPE.;
%mend mwe;
Notice I moved the call symput before the set. Yes, vtype() works fine even before set - the variables are still defined in the PDV even before anything happens in the data step.
(I also took out the spurious put statement that never will do anything as no TYPE variable is ever created in either version.)
An alternative approach is to use the vartype function instead, which does not require a set statement and unlike the vtype function can be used in pure macro code outside a data step (without resorting to dosubl or the like).
What all this means in practice is that you can use vartype to make a function-style macro version of vtype, like so:
%macro vtype(ds,var);
%local dsid varnum rc vartype;
%let dsid = %sysfunc(open(&ds));
%let varnum = %sysfunc(varnum(&dsid,&var));
%let vartype = %sysfunc(vartype(&dsid,&varnum));
%let rc = %sysfunc(close(&dsid));
&vartype
%mend vtype;
/*Example*/
%put %vtype(emptyset,myvar);
/*Output*/
N