SAS - If-then macros in DDE - sas

I'm outputting three datasets to Excel via DDE (set1, set2, set3). The datasets have the same variables, except that set3 has two additional variables. I've wrapped the DDE section in a macro that I call for each dataset and use "put" to write out the variables I want. I'm trying to figure out how to add the two additional variables from set3 if the macro is being called on set3. Here is my code so far:
filename out dde
'excel|sheet1!r2c2:r1000c5';
%macro write(set);
data _null_;
set &set.;
file out dlm='09'x;
put
var1
var2
var3
%if &set. = set3 %then var4 var5;
%else ;
run;
%mend write;
%write(set1);
%write(set2);
%write(set3);
The code works fine if I remove the macro %if-%then statement. Any ideas how to go about this? Thanks!

There isn't an ending semi-colon for the PUT statement, just for the %if and %else statements.
I find that it helps make the code clearer if I indent the macro code independently from the SAS code. Also when a SAS statement takes more than one line to make sure the put the terminal semi-colon on a separate line.
You can even add in some redundant macro %do; and %end; to help make it clearer which statements are macro statements and which are SAS statements. Or in this case parts of a SAS statement.
%macro write(set);
data _null_;
set &set.;
file out dlm='09'x;
put var1 var2 var3
%if &set. = set3 %then %do;
var4 var5
%end;
;
run;
%mend write;

Related

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;

Rename a external file in a SAS macro

I am getting a generic 'Statement not valid or out of order' message with the below:
%macro test;
data _null_;
%if %sysfunc(fileexist("C:\report_201809.xlsx")) = 1 %then %do;
rc=%sysfunc(rename("C:\report_201809.xlsx",
"C:\report_201809.xlsx"_old.xlsx",'file'));
%end;
%mend;
%test;
The code below should get you what you need. While you can use %if statements in a data step you generally won't need to. I'm guessing the error is coming from the %sysfunc function around the fileexist and rename functions. %sysfunc allows you to call data step functions outside of a data step so it is not needed here.
%macro test;
data _null_;
if fileexist("C:\file.txt") then do;
rc = rename("C:\file.txt", "C:\file2.txt", 'file');
end;
run;
%mend;
Alternatively, you could use an X Command that allows you to execute Windows commands. You could replace the rename function with the following statement.
x move C:\file.txt C:\file2.txt;
Remove the DATA _NULL_ or proceed per #J_Lard.
Macro arguments used in %sysfunc invoked function calls are implicitly quoted and do not need additional ' or "
%macro test;
%local rc;
%if %sysfunc(fileexist(C:\report_201809.xlsx)) = 1 %then %do;
%let rc = %sysfunc(rename(C:\report_201809.xlsx,C:\report_201809_old.xlsx,file));
%end;
%test;
You original code may have worked (by way of non-obvious side effect) if the filename "C:\report_201809.xlsx"_old.xlsx" (having an extraneous ") was corrected to "C:\report_201809_old.xlsx"

Two statements in one code (choosing by PROMT variable

I have to different statements in one code. For example:
First:
data step2;
set ste1;run;
proc print data=step2;quit;
Second:
data step6;
set ste5;run;
proc print data=step5;quit;
Is it possible to choose by PROMPT variable which one of them I need to Execute?
Assuming you mean a stored process prompt variable, you can simply build a macro:
%macro choose;
%if &mypromptvar=1 %then %do;
data step2;
set ste1;run;
proc print data=step2;quit;
%end;
%if &mypromptvar=2 %then %do;
data step6;
set ste5;run;
proc print data=step5;quit;
%end;
%mend;
%choose;
where mypromptvar is the name of your promptvariable...

SAS conditional logic to execute another sas program based on condition

I have a dataset naming error_table as follows. All the variables are character
Errorno Error Resolution
001 login check
002 datacheck check
I wanted a logic that executes a sas program If the Errorno is not in 001 and 002. Else stop execution and display the error_table.
I tried the following
%macro test();
proc sql;
select trim(Error_No) into: num from error_table;
quit;
%if &num. not in ("001","002") %then %do;
%include "/path/dev/program.sas";
%end;
%else %do;
proc print data = error_table;
run;
%end;
%mend;
%test;
But, it is throwing an error.
Can anyone please correct the logic.
You need to watch out for the case when the SELECT returns zero rows. You should set a default value to the macro variable NUM.
Is your dataset variable numeric or character? Use the TRIMMED or SEPARATED BY clause instead of the TRIM() function to prevent spaces in the macro variable that is generated by the INTO clause.
%let num=NONE;
select Error_No into: num trimmed from error_table;
Remember that to the macro processor everything is a string so don't but quotes around the values you are trying to match unless they are actually part of the value.
%if NOT (&num. in (001,002)) %then %do;
Also to use the IN operator in macro code you need to make sure you have set the MINDELIMITER option.
I would sugest moving condition with error codes to proc sql.
proc sql;
select count(*) into :num_errors
from error_table
where Errorno in ("001", "002");
quit;
Then in macrovariable you have number of errors that are 001 or 002.
Next step is to check macro-condition:
%if &num_errors. > 0 %then %do;
%include "/path/dev/program.sas";
%end;
%else %do;
proc print data = error_table;
run;
%end;
%mend;

SAS Macro for multiple datasets

I am new to SAS. I have 12(Monthly data) data sets in a folder.
Names of data sets are:
201401
201402
201403
...
201411
201412
Each data contain 10 Variables. Variable names are same for all data.
I want only 3 Variables among 10 and rename data by new_201401 and so on.
I am trying it manually by using Keep Var1 Var2 Var3; but is there any easy way or macro so we can make it fast? Thanks in advance.
I think this will do the trick:
%macro keep(table,var1,var2,var3,set);
data &table (keep=&var1 &var2 &var3);
set &set;
run;
%mend keep;
You can rename them using the following macro (note: the %if conditions are just split out to include a leading 0 for single digit months):
%macro monthly(year=,prefix=) ;
%do i=1 %to 2 ;
%if %eval(&i<10) %then Data_&year.0&i=&prefix&i ;
%else Data_&year&i=&prefix&i ;
%end ;
%mend monthly ;
You can then then for example pass these values into proc datasets for whatever years you need:
proc datasets library=work ;
change %monthly(year=2014,prefix=new_) %monthly(year=2015,prefix=new2_);
run ;