SAS code to copy a file based upon a condition check? - macros

Hello my requirement is for a pharma company.
Requirement goes as:
The SAS job is run on a daily basis, with some reject validations applied.
The rejected data goes to a specific reject folder. Now we have been asked to create a code where in the code "checks if a folder exists at a location with name as current date (today date) and if not , it should create it and put the rejected data files from the REJECT FOLDER to the date folder created (I have the code for folder creation.)
Now here is the catch, Other developer shall write the code by which today date shall be appended at the end of the filename as yyyymmdd format.
I need to check the file WITH CURRENT DATE AT LAST AND PUT IT IN THE CURRENT DATE FOLDER.
E.g file is c:\sas\xxxaaaa_20140716.dat , the file should be copied to c:\reject\20140716\ folder.
I have developed a code that checks the existence and create a folder with name as today date.
Please help me to write a code in between to move the files upon the condition.
P
.S. I am new to SAS coding so would appreciate an exact code.Thank You
Code:
%macro fcheck(dir=) ;
options noxwait; %* no need to wait for command prompt action from user;
%local var fileref ;
%let var = %sysfunc(filename(fileref,&dir)) ;
%if %sysfunc(fexist(&fileref)) %then %* to check if the file xists;
%put NOTE: The directory "&dir" exists ; %* here we can put a statement to move our reject file to the date folder;
%else
%do ;
%sysexec md &dir ; %* create the directory as our current date;
%put %sysfunc(sysmsg()) The directory has been created. ; %*this message may not be required for us;
%end ;
%let var=%sysfunc(filename(fileref)) ;
%mend fcheck ;
%let sascode=%sysfunc(date(), yymmddn8.);
%fcheck(dir=c:\dir) ; %* directory specification goes here ;
%fcheck(dir=c:\dir\&sascode);%* checkin my directory path and name

Couple of methods to copy files in SAS:
xcommand (this will use the dos system to copy files)
X "copy c:\temp\*.* C:\temp\CopyFiles\*.* > C:\temp\CopyFiles\reportcp.txt";
And systask:
systask command "copy c:\temp\*.* C:\temp\CopyFiles\*.*" wait status=copyfl;
Be aware that systask runs asynchronously with SAS, therefore if you need to wait for the result of the SYSTASK command before you continue you'll need to use WAITFOR or WAIT options

Related

Sending automated email from SAS with attachments that changes name

I have files that should be send out every week. These files changes names e.g. "filename_1" next week it will be "filename_2".
But it only takes the filename that I manually wrote which is filename_1. Is there a way to say that it should take the latest file with this name everyweek,instead of me doing it manually every week?
This is my code for the email (I manually wrote the filename):
filename outbox email from="test#test.dk" to="test#test.dk"
type='text/html' subject='test' attach=("F:\filename_1.png" ct='png')
ods html body=outbox rs=none style=Htmlblue;run; ods html close;
The SAS macro facility will help you solve this very problem. If your filenames always have a consistent pattern, you can assign a macro variable to automatically change it for you. For simplicity's sake, let's say your filename always ends with today's date. You can assign a macro variable to hold this value.
%let filename = filename_&sysdate9..png;
This will resolve to filename_14DEC2020.png. You can confirm it with %put &filename.
If your file is sent out weekly and increments in a pattern, some quick math will help us figure out the correct suffix. Let's set a base week to start. We can count the number of weeks from this base week to identify the suffix. In this case, let's say it's today: December 14th, 2020. intck() can count the number of weeks from then until today. Our logic is:
suffix = (Number of weeks from Dec. 14th 2020 to Today) + 1.
In data step language, this is:
suffix = intck('week', '14DEC2020'd, today() ) + 1;
Translated to SAS macro language:
%let suffix = %sysevalf(%sysfunc(intck(week, %sysfunc(inputn(14DEC2020, date9.)), %sysfunc(today()) )) + 1);
%let filename = filename_&suffix..png;
Because we're pulling from data step functions, we need to enclose nearly everything in %sysfunc() to call them. This is one of the functions available that connect the SAS macro facility with the data step language.
Note that we also cannot use date literals directly in the SAS macro facility. We must use inputn() or putn() to convert a human-readable date into a SAS date format.
Simply call this macro variable within your code and it will resolve automatically (except within single quotes).
filename outbox email
from="test#test.dk" to="test#test.dk"
type='text/html'
subject='test'
attach=("F:\&filename" ct='png')
;

SAS include dynamic path

I have tryed build little macro which in loop it should runother SAS programs.
Table Control_files has two field, where are other part of path to proper sas program.
%LET PATH_TO = '%include "T:\XXX\YYY\ZZZ\';
%LET PATH_end = '.sas"';
data _null_;
set CONTROL_FILES;
call execute ('%runlimitsquery('||&PATH_TO||SCHEMA_NAME||'\'||PROCES_NAME||&PATH_end||');');
run;
I tryed used runlimitsquery because I found somewhere that tip..
When I run my code, log returns:
NOTE: CALL EXECUTE generated line.
NOTE: Line generated by the CALL EXECUTE routine.
1 + %runlimitsquery(%include "T:\XXX\YYY\ZZZ\XXX_TECHNICAL_AAAAA\001_AAAAA.sas");
_
180
WARNING: Apparent invocation of macro RUNLIMITSQUERY not resolved.
ERROR 180-322: Statement is not valid or it is used out of proper order
Anyone can help me?
Ok, I have answer for my problem...
Below code works:
%LET PATH_TO = '%include "T:\XXX\YYY\ZZZ\';
%LET PATH_end = '.sas"';
data _null_;
set CONTROL_FILES;
call execute ('('||&PATH_TO.||SCHEMA_NAME||'\'||PROCES_NAME||&PATH_end.||';');
run;

SAS: Rename a Macro Catalog

I want to store macros in a catalog. Doing so allows many macros to be shared with just a single file, as well as introduces a degree of separation from the user.
To store my macro, I run a program such as
/* HelloWorld.sas */
libname pwd "."; /* assign current directory */
option mstored sasmstore=pwd; /* set pwd as storage directory */
%macro HelloWorld()
/ store source; /* store compiled macro along with its source */
data _null_;
put "Hello, World!";
run;
%mend;
This creates a sasmacr.sas7bcat file in the directory in which HelloWorld.saslives. I can then move that file to another directory, such as C:\myMacrosand run the following program:
/* CallHelloWorld.sas */
libname myMacros 'C:\myMacros';
option mstored sasmstore=myMacros;
%HelloWorld();
The macro HelloWorld() is called without error.
However, if I want to consider the HelloWorld() macro as part of a "HelloWorld" macro suite, I cannot simply change the catalog name in Windows Explorer from sasmacr.sas7bcat to HelloWorld.sas7bcat. When I do this and try running CallHelloWorld.sas again (after closing and reopening SAS), the macro is not resolved.
1 /* CallHelloWorld.sas */
2 libname myMacros 'C:\myMacros';
NOTE: Libref MYMACROS was successfully assigned as follows:
Engine: V9
Physical Name: C:\myMacros
3 option mstored sasmstore=myMacros;
4
5 %HelloWorld();
-
180
NOTE: The SAS System was unable to open the macro library referenced by the SASMSTORE = libref
MYMACROS.
WARNING: Apparent invocation of macro HELLOWORLD not resolved.
ERROR 180-322: Statement is not valid or it is used out of proper order.
ERROR: Catalog MYMACROS.SASMACR does not exist.
NOTE: The SAS System was unable to open the macro library referenced by the SASMSTORE = libref
MYMACROS.
ERROR: An error occurred during the execution of the %COPY statement.
How do I change the name of a catalog which contains macros so that those macros may be called in various programs? Is it possible to name the catalog something different than sasmacr up front?
At least on Unix with SAS 9.4 you can use the SASAUTOS option to point at a FILEREF that uses the ZIP engine so that all of the macro definitions are stored in a single ZIP file.
The one "trick" is that you need to change the names of the member files in the ZIP file. Normally on unix SASAUTOS requires that the source files are named using the macro name in lowercase with a .sas extension (helloworld.sas). But for SASAUTOS to work with a ZIP file the members should be named using the macro name in uppercase with NO extension (HELLOWORLD).
filename mymacros zip '~/mymacros.zip';
options insert=(sasautos=(mymacros)) ;
EDIT
Unfortunately this method causes SAS to generate ERROR: messages when the macro source file is not found in the ZIP file, even if it is ultimately found in another file in the SASAUTOS option search path.
I don't think you can rename the catalog away from SASMACR and still use it directly. However, you could use PROC CATALOG potentially to manage the SASMACR catalog.
What you'd want to do is, when you wanted to include a particular macro, copy it via proc catalog from its source location into your chosen SASMSTORE location.
Something like:
libname myMacros 'C:\temp';
libname pwd '.';
options mstored sasmstore=pwd;
proc catalog catalog=myMacros.HelloWorld;
copy out=pwd.sasmacr;
run;
quit;
%HelloWorld();
Now - I would suggest this is probably overkill; there's really no reason to have separate macro catalogs this way. If you like the idea of separately including files, you may want to consider Autocall macros (where you don't store them compiled, but store their source and compile-on-demand); really compiling a macro costs nearly nothing in SAS anyway. But if using stored-compiled macros is what you like, this method is probably the best way to do it.
Of course, I think an easier way would be to leave the catalog SASMACR.SAS7BCAT and use the directory name to determine what it is, and then append librefs to your sasmstore option value.
From DATA_NULL_ I have received the answer to how to use to existing catalogs with different names. Use the CATNAME statement. So if you have catalogs TEST.CAT1 and TEST.CAT2 you can use the CATNAME statement to make TEST.SASMACR be the concatenation of the two macros.
CATNAME test.sasmacr
(test.cat1 (ACCESS=READONLY)
test.cat2 (ACCESS=READONLY)
)
;
You can now point the SASMSTORE option the the TEST libref.
option mstored sasmstore=test;
Here is an example of how you might create such separate catalogs using PROC CATALOG to copy members that have been compiled into a SASMACR catalog into catalogs with different names.
libname templib '~/test/cat1';
libname permlib '~/test';
options mstored sasmstore=templib;
%macro HelloWorld1() / store source;
data _null_;
put "Hello, World! &sysmacroname";
run;
%mend;
%macro HelloWorld2() / store source;
data _null_;
put "Hello, World! &sysmacroname";
run;
%mend;
proc catalog cat=templib.sasmacr ;
copy out=permlib.cat1;
select helloworld1 /et=macro;
run;
copy out=permlib.cat2;
select helloworld2 /et=macro;
run;
quit;
Now use the CATNAME command to chain the catalogs together.
options mstored sasmstore=permlib;
CATNAME permlib.sasmacr
(permlib.cat1 (ACCESS=READONLY)
permlib.cat2 (ACCESS=READONLY)
);
%helloworld1;
%helloworld2;

SAS Macro not detecting a file

CMS released a SAS macro that checks for the existence of a file:
** check existance of dataset**;
%macro CHECKDS(FILE,LONGFILE);
%if %sysfunc(exist(&FILE)) %then;
%else %do;
data _null_;
file print ls=255;
&MSG30 put "ERROR : [Msg30] Program halted, file &LONGFILE does not exist";
abort; run;
%end;
%mend CHECKDS;
Now when I call it with this:
LIBNAME IN1 "/folders/myfolders/";
%CHECKDS(&STPERSON.TXT,PERSON)
run;
I get this error: ERROR : [Msg30] Program halted, file PERSON does not exist.
I know that the files exists and is in that location. Any ideas?
The first argument to the exist function should be in the format libname.memname. The second argument to the exist function specifies the member type; since you didn't specify the member type, the default, DATA, is assumed. This implies a file with a SAS data file with a sas7bdat extension.
See here for a list of member types.
Since your file is a .txt file, I don't think it can be considered a library member. Anyone is welcome to correct me if I'm wrong.
DWal got it right above. Here's a more complete answer for what I had to do. I had to convert the .txt file to a sas data set (particularly .sas7bdat).
proc import datafile="/folders/myfolders/PERSON"
dbms=dlm
out=person
replace;
delimiter=' ';
getnames=yes;
run;
Then that had to be written to my library and I was able to use it.
data IN1.person ;
set person;
run;

How to write macro for importing multiple excel files(xlsx) in sas and append it

I am having some 50 excel files (xlsx format) to be imported to sas and then need to append it for analysis. All the excel files header are same i.e., the variable names are same for all the file. I need macro for importing and appending all of them at a time rather than importing all the files one by one and then later append it. Your help is much appreciated.
The other issue with the excel file is that there is a blank column next between the variable name and data points. I have written a code remove it using data step but came we write this also in the macro while importing.
Data XXX.yyy;
Set XXX.yyy;
if missing(coalesceC(of ASC Brand Cdesc1 Cust_ DGM Desc Family Grp1 High_Level_Product_Desc
Issf Name Prod_Desc Product__Code RVP SA_Desc Terr_ UOM Yr
)) and missing(coalesce(of Acc Int_Margin M_Cost Mth Net_Sales Sls__ Uts )) then delete;
run;
It sounds as though your existing code already does what you need it to do. I doubt there will be much of a performance gain from attempting to import all 50 files in one data step (which is possible via dde, but rather fiddly).
If your existing code is set up to process just one hard-coded file, I'd suggest using it to write a simple macro that takes one excel file as input, imports that file, and appends it to the master dataset. Then you can call the macro 50 times.
e.g. You could write the macro as something like this, incorporating all the relevant bits of your code, and replacing all references to specific files with macro variables:
%macro import_and_append(excel_file,base_dataset);
proc import datafile = "&excel_file" dbms = excel out = t_import;
run;
proc append base = &base_dataset data = t_import;
run;
proc datasets lib = work nolist nowarn;
delete t_import;
run;
quit;
%mend;
Then you can call the macro like so:
%import_and_append(c:\excel_file_01.xls,work.master_dataset)
Another way to do this would be to use the Excel LIBNAME Engine. You declare a library to each of your files, and then read all the sheets in 1 Data Step.
In this example, I have 2 workbooks (Book1.xlsx and Book2.xlsx) in C:\temp. All data is in Sheet1. 3 variables -- X, Y, and Z. Modify as needed for your purpose.
data files;
format file $12.;
input file $;
datalines;
Book1.xlsx
Book2.xlsx
;
run;
%macro read_excel(dir,outdata,files);
data _null_;
set &files end=last;
call execute("libname t" || strip(put(_n_,8.)) || " excel '&dir\" || strip(file) || "';");
if last then
call symput("n",_n_);
run;
data &outdata;
set
%do i=1 %to &n;
t&i.."Sheet1$"n
%end;
;
a = sum(x,y,z);
if missing(a) then delete;
run;
%do i=1 %to &n;
libname t&i clear;
%end;
%mend;
%read_excel(c:\temp,data_from_excel,files);