I have a SAS EG program that checks if a file exists and refuses to replace it if it dose exists.
When this happens I want SAS EG to show an error on that program and display a meaningful custom error message in the log. And I want the error message to look the same as other error messages people are used to seeing in the log so they pay attention to it.
For now I have just imported a file with a name of my error message. This is not great because it appends file not found messages to the message I want to display.
Is there any way I can declare that there is an error and provide an error message to put in the LOG
The SAS log uses a very simple way to change text color: the first word in the line of text to display in the log. You can recreate ERROR, WARNING, and NOTE messages in both %put and put statements.
%put NOTE: This is a note;
%put WARNING: This is a warning;
%put ERROR: I AM ERROR;
For example, let's say you want to display an error if a certain value is missing.
data have;
input var;
datalines;
1
.
2
3
.
;
run;
%put NOTE: Now checking for missing values...;
data _null_;
set have;
if(missing(var) ) then
put 'ERROR: A missing value for "var" was found at observation ' _N_;
run;
You can also do this with macros, such as creating a flag during certain check steps, or using the &syserr automatic macro variable.
%macro check;
%let e = 0;
data _null_;
set have;
if(missing(var) ) then call symput('e', 1);
run;
%if(&e) %then %put ERROR: An error was found.;
%mend;
Related
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
I'm having basically the same issue as the following post:Proc Data sets argument error- Error 22-322 expecting a name
But the answer didn't solve my problem.
%let _EFIERR_ = 0; /* set the ERROR detection macro variable */
libname indata "E:\el30053_54_55\el30053-postprocessor\output\files";
/* Format HYPO1001 variables */
PROC datasets library=INDATA;
MODIFY INDATA.hypo1001
/* Format section. */
format HYPOR1;
/* Should not need to edit anything below. */
run;
quit;`
Essentially, I have several datasets in the library INDATA. One of them is called hypo1001. Bottom line, I need to rename some of the variables in the dataset, but the rename statement isn't working because there are a few variables with invalid formats. So now I'm trying to fix the formats, but it doesn't seem to be working. From what I can tell, my syntax is correct, but I have very limited experience with SAS that doesn't usually extend much beyond just converting xpt files to SAS format.
I'm getting the following errors in the log:
ERROR 22-322: Expecting a name.
ERROR 201-322: The option is not recognized and will be ignored.
The libref you used to define the library should not be included in the member name that you use in the MODIFY statement. Try this example:
data class; set sashelp.class; run;
proc datasets nolist lib=work;
modify class ;
format name ;
run;
quit;
I want to change dataset names in SAS using concatenated macro variables. Using the example code below I get an error. Is my syntax wrong or is it not possible to use a concatenating function in this way?
Code:
%let term=201610;
%let emp='bob';
Proc Datasets library=work;
change testset = cat(&emp,&term);
run;
Errors Received:
ERROR 22-322: Syntax error, expecting one of the following: ALTER, MEMTYPE, MT, MTYPE, PROTECT, PW, READ, WRITE.
ERROR 76-322: Syntax error, statement will be ignored.
You don't need to concatenate macro variables, it's like a find and replace text.
Because you have quotes right now this is what would happen:
change testset = cat('bob', 201610)
But the CAT function is not valid there. You could technically use %SYSFUNC() to use the CAT function but there's an easier way.
%let term=201610;
%let emp='bob';
Proc Datasets library=work;
change testset = &emp&term.;
run;quit;
Note that PROC DATASETS requires a QUIT to terminate.
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*/
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(...).