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.
Related
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;
If the dataset dataset_1&x._&y. exists, I want to get data from it, but if it doesn't exist i want to get data from dataset_2.
I have tried the following macro but it doesn't work:
%macro test(x,y);
%if %sysfunc(exist(dataset_1_&x._&y.)) %then %do;
data final_data;
set dataset_1_&x,_&y.;
run;
%end;
%else %do;
data final_data;
set dataset_2;
run;
%end;
%mend;
Try this - no need to define a macro:
%let exist=%sysfunc(exist(work.dataset_1&x._&y.));
%let inds=%sysfunc(ifc(&exist=1,work.dataset_1&x._&y.,work.dataset_2));
data work.final_data;
set &inds;
run;
If you did want a macro to see if a dataset (or view) exists, you could use this one: https://core.sasjs.io/mf__existds_8sas.html
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;
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;
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.