SAS - how to not import empty file - sas

I am trying to import all the CSV files in one folder and schedule the program in the SAS management console. Since it has empty CSV files in the folders, it failed to run the code automatically due to the errors. I was wondering if I can skip the steps of importing the empty file in the following codes.
`%macro drive(dir,ext);
%local cnt filrf rc did memcnt name;
%let cnt=0;
%let filrf=mydir;
%let rc=%sysfunc(filename(filrf,&dir));
%let did=%sysfunc(dopen(&filrf));
%if &did ne 0 %then %do;
%let memcnt=%sysfunc(dnum(&did));
%do i=0 %to &memcnt;
%let name=%qscan(%qsysfunc(dread(&did,&i)),-1,.);
%if %qupcase(%qsysfunc(dread(&did,&i))) ne %qupcase(&name) %then %do;
%if %superq(ext) = %superq(name) %then %do;
%let cnt=%eval(&cnt+1);
%put %qsysfunc(dread(&did,&i));
proc import datafile="&dir\%qsysfunc(dread(&did,&i))" out=dsn&cnt
dbms=csv replace;
guessingrows=max;
run;
data dsnnew&cnt (drop=old);set dsn&cnt (rename=(party_id = old)); party_id= input(old,12.);run;
%end;
%end;
%end;
%end;
%else %put &dir cannot be opened.;
%end;
%let rc=%sysfunc(dclose(&did));
%mend drive;`

PROC IMPORT cannot handle CSV files with fewer then 2 lines. You could just count how many lines the file has. No need to count beyond 2.
data _null_;
if eof then call symputx('nobs',_n_-1);
infile "&dir\%qsysfunc(dread(&did,&i))" obs=2 end=eof;
input;
run;
You can then test the value of the NOBS macro variable to decide whether or not to run PROC IMPORT>
%if &nobs>1 %then %do;
....
%end;
If the files all have the same structure then there is no need for the complicated macro code. Instead just read them all with one data step. You will have to write the code, but you will then have full control over how the variables are defined. You could include the actual name of the file as part of the dataset. Or perhaps extract some identifying information from the filename.
data want;
length fname filename $256 ;
infile "&dir/*.csv" filename=fname truncover dsd ;
input #;
* skip the header lines ;
if fname ne lag(fname) then delete;
* save the filename to a permanent variable;
filename=fname;
* Here is where you put the code to actually read the lines ;
input var1 var2 .... ;
run;

Related

How to conditionally %include a *.sas file that defines a macro?

I use a macro in several SAS programs, so I defined it in a separate file /myFolder/myMacro.sas.
When running in batch, I want to use it this way: %include '/myFolder/myMacro.sas;'
When testing changes to the code in Enterprise Guide, I wan to edit and run /myFolder/myMacro.sas, then edit and run the programs that use it. How do I conditionally include the macro definitions?
%if &server = BATCH_SERVER %then %include '/myFolder/myMacro.sas;' does not work: The file is included anyway and the %if statement is applied to the comment on top of the file and results in
ERROR: Expected %DO not found.
ERROR: Skipping to next %END statement.
Just use a %then %do
%let mode=BATCH;
filename mac1 temp;
filename mac2 temp;
data _null_;
file mac1;
put '%macro mac1;%put mac1;%mend;%mac1;';
data _null_;
file mac2;
put '%macro mac2;%put mac2;%mend;%mac2';
run;
%if &mode=BATCH %then %do;
%inc mac2;
%end;
%else %do;
%inc mac1;
%end;
As I suspected, the error occurs because the include file starts with comments, somthing like:
* MyMacro is written to do this and that *;
* ************************************** *;
%macro MyMacro;
proc this;
proc that;
run;
%mend;
So after including the file, this becomes
%if &server = BATCH_SERVER %then * MyMacro is written to do this and that *;
* ************************************** *;
%macro MyMacro;
proc this;
proc that;
run;
%mend;
which is invalid.
When working inside a macro: add %do; and %end;
As Allan suggested, it is sufficient to put the %inlcude between %do; and %end;
%if &server = BATCH_SERVER %then %do;
%include '/myFolder/myMacro.sas;'
%end;
So after including the file, this becomes
%if &server = BATCH_SERVER %then %do;
* MyMacro is written to do this and that *;
* ************************************** *;
%macro MyMacro;
proc this;
proc that;
run;
%mend;
%end;
which works.
When working in open code: use call execute
data _null_;
if "&mode"="BATCH" then call execute ("%include /myFolder/myMacro.sas;");
run;
%DoIt;

How to run part of macro based on number of observations in work file in SAS

I'm pretty new to doing macros on SAS so apologies in advance if my questions seems basic.
I'm looking to execute part of a macro if there are a minimum number of observations found in temporary work file.
If there are a minimum number of observations, the macro should execute a proc export of that temporary work file, otherwise it will just produce an error message on the log.
I'm not sure what I'm doing wrong, the temporary work file has more than 1 observation and I want the macro to run, however it produces the error message as if it has less than the minimum.
Below is the code that I've created so far - any help you have to offer will be greatly welcomed.
data original_data;
set data.dataset;
keep column1 column2 column3 ;
run;
%macro test_macro;
%let dsid=%sysfunc(open(work.original_data));
%let nobs=%sysfunc(attrn(&dsid,nobs));
%let dsid=%sysfunc(close(&dsid));
%if &nobs >1 %then %do;
%put ERROR: No observations counted;
%return
%end
%else %do;
proc export data=submissions
outfile='C:\Users\myusername\Desktop\test.csv'
DBMS=csv replace;
run;
%end;
%mend test_macro;
%test_macro
Missing semicolons on RETURN and END statements
Logic is reversed. You're putting the error message if you have more than one observation. Flip your code so that you export if you have more than one observation.
options mprint symbolgen;
%macro test_macro;
%let dsid=%sysfunc(open(work.original_data));
%let nobs=%sysfunc(attrn(&dsid, nobs));
%let dsid=%sysfunc(close(&dsid));
%put &nobs;
*if more than one observation;
%if &nobs > 1 %then
%do;
proc export data=sashelp.class outfile='/home/fkhurshed/test.csv' DBMS=csv
replace;
run;
%end;
%else
%do;
%put ERROR: No observations counted;
%return;
%end;
%mend test_macro;
%test_macro;

Some problems appear when i use Macro variable

data classivar_1;
set classvar;
AnaClassVar=scan(scan(F2,1," "),2,".");
run;
proc sql;
select AnaClassVar into : MacClassVar separated by "#" from classivar_1 ;
select count(*) into: Count_classvar from classivar_1;
quit;
%put &MacClassVar.;
%put &Count_classvar.;
ods output variables=adsl_var;
proc contents data=ev.adsl;
run;
proc sql;
select variable into : AllVar separated by "#"
from adsl_var;
select count(*) into : Count_Allvar from adsl_var;
quit;
%put &Allvar.;
%put &Count_Allvar.;
**** set up Macro ClassAna to analyze the classified varialbes;
%macro ClassAna(datasets= );
%do i= 1 %to &Count_classvar.;
%do count=1 %to &Count_Allvar;
%if %sysfunc(find(%scan(&MacClassVar,&i,#),%scan(&AllVar,&count,#)))
%then %do;
%let Class_var&i.=%scan(&AllVar,&count,#);
%end;
%end;
%put &&Class_var&i..;
%end;
%Mend;
%ClassAna(datasets=sashelp.class)
When I submit the programme , the macro variable Class_var6 cannot be resolved.
But other macro variables can be resolved correctly.
The logs are in the picture.enter image description here
enter image description here
In %ClassAna you are conditionally creating the macro vars based on:
%if %sysfunc(find(%scan(&MacClassVar,&i,#),%scan(&AllVar,&count,#)))
%then %do;
That FIND is case sensitive by default. I think it will work if you make it case insensitive by adding the optional i parameter to FIND. Something like:
%if %sysfunc(find(%scan(&MacClassVar,&i,#),%scan(&AllVar,&count,#),i))
%then %do;
Or you could %upcase both variable lists and leave the FIND as is.

SAS - check if external file (.csv) is empty; if not, import into SAS

I have several .csv files in a folder that I would like to import into SAS. However, they are not always populated with data, so when I attempt to import an empty file into SAS, I get an error. I am wondering if there is some way for me to check whether or not an external file is empty, and if it is not, bring it into SAS. This is a code that I would like to automate and not have to manually check and account for blank files every time.
I came across this macro in SAS's knowledge base but am unsure of how to modify it so that it would import a .csv file, if I should be using it at all: http://support.sas.com/kb/25/072.html
I appreciate your help.
This is the macro in question from the link:
%macro test(outf);
%let filrf=myfile;
%if %sysfunc(fileexist(&outf)) %then %do;
%let rc=%sysfunc(filename(filrf,&outf));
%let fid=%sysfunc(fopen(&filrf));
%if &fid > 0 %then %do;
%let rc=%sysfunc(fread(&fid));
%let rc=%sysfunc(fget(&fid,mystring));
%if &rc = 0 %then %put &mystring;
%else %put file is empty;
%let rc=%sysfunc(fclose(&fid));
%end;
%let rc=%sysfunc(filename(filrf));
%end;
%else %put file does not exist;
%mend test;
%test(c:\test.txt)
What you'd want to do is change what the macro does in the case that the file is empty. In this case, the fget will return a 0 to the return code (%let rc = ... fget) if it is able to get a string, or it will fail and return a nonzero code.
So, just modify the %if / %else. Instead of putting something, you just do something like
%if &rc=0 %then %do;
%import_csv(&outf.);
%end;
%else %do;
%put File &outf. is empty.;
%end;
That assumes you have a macro that does your import. You could, of course, include the full PROC IMPORT code there instead.
This really makes a reasonable error checking wrapper to an import macro, in fact.
%macro import_csv(outf=,outds=);
%let filrf=myfile;
%if %sysfunc(fileexist(&outf)) %then %do;
%let rc=%sysfunc(filename(filrf,&outf));
%let fid=%sysfunc(fopen(&filrf));
%if &fid > 0 %then %do;
%let rc=%sysfunc(fread(&fid));
%let rc=%sysfunc(fget(&fid,mystring));
%let rc_close=%sysfunc(fclose(&fid));
%if &rc = 0 %then %do;
proc import file="&outf." out="&outds."
dbms=csv replace;
run;
%end;
%else %put File &outf. is empty and not imported.;
%end;
%let rc=%sysfunc(filename(filrf));
%end;
%else %put file does not exist;
%mend test;

Trying to create a macro with If-Then conditions in SAS

Here is the code I'm using to creat a format.....
libname myfmt "&FBRMrootPath./Formats";
%macro Create_Macro(DSN,Label,Start,fmtname,type);
options mprint mlogic symbolgen;
%If &type='n' %then %do;
proc sort data=&DSN out=Out; by &Label;run;
Data ctrl;
set Out(rename=(&Label=label &Start=start )) end=last;
retain fmtname &fmtname type &type;
%If last %then %do;
hlo='O';
label='*ERROR';
output;
%End;
%End;
%Else %do;
proc sort data=&DSN out=Out; by &Start;run;
Data ctrl;
set Out(rename=(&Start=label &Label=start )) end=last;
retain fmtname &fmtname type &type;
output;
%If last %then %do;
hlo='O';
label='*ERROR';
output;
%End;
%End;
proc format library=myfmt cntlin=ctrl;
%Mend Create_Macro;
%Create_Macro(SSIN.prd,prd_nm,prd_id,'prd_test','n');
/*%Create_Macro(SSIN.prd,prd_id,prd_nm,'prd_testc','c');*/
I'm getting following errors...Code looks good but I donno why I'm getting errors...
Any help???
Not entirely sure what you are doing, but the error message is probably because you are mixing macro code with data step code. Trying change to this:
if last then do;
hlo='O';
label='*ERROR';
output;
end;
In other words, get rid of the ampersands (which indicate macro variable references).
And also be sure to add a run; statement at the end of each data step and after the PROC FORMAT call.