Monday, January 22, 2018

Hack 7.3 Concatenating Multiple Directories in a LIBNAME Statement




SAS Programming Professionals,

Did you know that you can concatenate multiple directories together in a LIBNAME statement?

Most programs have a 1-to-1 correlation between a LIBNAME statement and a SAS data library.  However, it doesn’t need to be that way in real life!  You can have multiple directories specified in a LIBNAME statement.  Consider this example:

libname ctemp ("c:\temp", "c:\temp\usertemp");

data class;
set  ctemp.class(where=(sex="M"));

run;

proc sort data=class out=ctemp.sortedmales;
      by descending age;
run;

libname ctemp list;

In the example, we are concatenating two directories (c:\temp and c:\temp\usertemp) together to form the CTEMP SAS data library.  When you use “CTEMP” as the first level of a two-level SAS data set name, SAS will search first c:\temp, and then c:\temp\usertemp for that SAS data set.  If there is a SAS data set with the same name in both libraries, SAS uses the first one it comes across.

Check out the log from this program:

1    libname ctemp ("c:\temp", "c:\temp\usertemp");
NOTE: Libref CTEMP was successfully assigned as follows:
      Levels:           2
      Engine(1):        V9
      Physical Name(1): c:\temp
      Engine(2):        V9
      Physical Name(2): c:\temp\usertemp
2
3    data class;
4    set  ctemp.class(where=(sex="M"));
5
6    run;

The note highlighted in yellow, above shows that SAS recognizes the concatenation of the two directories to form one SAS data library.

NOTE: There were 10 observations read from the data set CTEMP.CLASS.
      WHERE sex='M';
NOTE: The data set WORK.CLASS has 10 observations and 5 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.01 seconds

The note highlighted in yellow, above shows that SAS read the CLASS data set from the CTEMP directory.  In fact, CLASS is located in c:\temp\usertemp, which is the second directory in the concatenation.

7
8    proc sort data=class out=ctemp.sortedmales;
9        by descending age;
10   run;

NOTE: There were 10 observations read from the data set WORK.CLASS.
NOTE: SAS sort was used.
NOTE: The data set CTEMP.SORTEDMALES has 10 observations and 5 variables.
NOTE: PROCEDURE SORT used (Total process time):
      real time           0.01 seconds
      cpu time            0.01 seconds

The note highlighted in yellow, above shows that SAS stored the SORTEDMALES data set in the CTEMP directory.  By default, SAS stores all new data sets in c:\temp, which is the first directory in the concatenation.


11
12   libname ctemp list;
NOTE: Libref=   CTEMP
      Scope=    DMS Process
      Levels=   2
        -Level 1-
      Engine=   V9
      Physical Name= c:\temp
      Filename= c:\temp
        -Level 2-
      Engine=   V9
      Physical Name= c:\temp\usertemp
      Filename= c:\temp\usertemp

In the example above, the LIST option on the LIBNAME statement is used to list the attributes of the CTEMP libref; including the directories that are concatenated together.

As long as you understand the rules of the road, (SAS processes the first data set it finds with a specific name when traversing the concatenated files; and SAS writes new data sets to the first directory in the concatenation) concatenating directories together for a single SAS data library can be very useful!

The hack above is an excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers

https://tinyurl.com/y83aleb4

Best of luck in all your SAS endeavors!

---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 

Michael A. Raithel's SAS Limerick #1

SAS Programming Professionals,


Something to make you smile while writing your programs today:

    At the corporate headquarters of a premier hotel,

    Managers had all of their data locked up in Excel,

    So they hired a SAS programmer named Miles,

    Who had SAS Access Interface to PC Files,

    Now they thoroughly understand their clientele.

Best of luck in all your SAS endeavors!


---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 


Monday, January 15, 2018

Hack 7.2 Capturing the Values of Windows Environmental Variables




SAS Programming Professionals,

Did you know that you can capture the name and value of Windows environmental variables with SAS?

Environmental variables are a class of variables created by the operating system to store values used by a wide variety of programs.  For example, the TEMP variable holds the value of the directory that all programs should use when creating temporary files.  On the Windows 7 workstation I am currently using, that value is C:\Users\Michael\AppData\Local\Temp.

Here is a very straight-forward program you can use to identify the Windows environmental variables and their values:

filename enviovar pipe 'set' lrecl=1024;

data work.xpset;

infile enviovar dlm='=' missover;

length name $ 32 value $ 100;

input name $ value $;

run;

proc print noobs;
title1 "Windows Environmental Variables for My Workstation";
run;
If you take a moment to run that program, you will find a fascinating array of environmental variables available to you. You can see the directory common programs are stored in, the path to your home directory, the number of processors your computer has, the processor architecture, the user name, and the directory where the user profile is stored.

You can capture and then use the Windows environmental variables in your SAS programs where you need to identify something particular to a Windows workstation or PC.  Or, you might choose to dump them into a flat file as a means of documenting the exact system that you were running SAS programs on—say in a clinical trials environment.  The Windows environmental variables are there for the using.  So, go ahead and use them!


The hack above is an excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers
https://tinyurl.com/y83aleb4

Best of luck in all your SAS endeavors!

---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 

Monday, December 4, 2017

Announcing the Launch of My Book of SAS Programming Hacks!


SAS Programming Professionals,

I am pleased to announce the publication of the print edition of my book:

Did You Know That?  Essential Hacks for Clever SAS Programmers!
https://tinyurl.com/y83aleb4

This book was previously published as an Amazon Kindle e-book.  But, I received a lot of requests for a print edition, so here it is.  And just in time for the holiday gift-giving season, too!

Best of luck in all of your SAS endeavors!

(aka Michael A. Raithel)




Monday, November 27, 2017

Hack 7.1 Avoiding File Lock Problems



SAS Programming Professionals,

Did you know that you can avoid those occasional, sporadic, annoying file lock wait errors on SAS for Windows by using a simple LIBNAME option?

Occasionally on SAS for Windows, the Microsoft DFS replication process unintentionally causes a lock on SAS data sets.  SAS does not wait for the lock to be released on the SAS data set and displays an error in the SAS log.  For Example:

libname timing "r:\path" ;

Proc sort data = timing.studyfil; 
by fncl_ast_id; 
run;

…could possibly produce the following error:

ERROR: A lock is not available for TIMING.STUDYFIL.DATA.

This happens because locks from third party software applications are not automatically checked by SAS’s internal FILELOCKWAIT facility. This particular error has occasionally been observed when the path to the SAS data library goes to a network drive, not to a C-drive.

To avoid this problem, use the libname option FILELOCKWAIT as follows:

libname timing "r:\path" filelockwait=10;


Note that filelockwait=  is in seconds and in most cases 10 seconds is enough. Also, don’t fret if you have never experienced this issue.  It is relatively rare and has not affected most SAS programmers.  But, now you are sufficiently armed in case you do encounter it.

Best of luck in all your SAS endeavors!

---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 

The hack above is an excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers

Monday, October 30, 2017

Hack 6.5 Jazzing Up Reports Using ODS Style Templates



SAS Programming Professionals,

The Output Delivery System (ODS) utilizes style templates (sometimes called “style definitions”) to render output.  Style templates describe the font face, size, color, and other attributes that are to be used when a report is rendered.  SAS currently has 58 individual style templates available for your use; and more are sure to be added moving forward.  If you do not specify a style template in your SAS program, ODS uses the aptly named Default style template.  Most of the time, Default is satisfactory.  However, there are some very nice alternatives!

You can get a listing of all of the style templates available to you by submitting the following:

proc template;

list styles;

run;

The output looks, in part, like this:

       Obs    Path                         Type
       -----------------------------------------
       1     Styles                       Dir
       2     Styles.Analysis              Style
       3     Styles.Astronomy             Style
       4     Styles.Banker                Style
       5     Styles.BarrettsBlue          Style
       6     Styles.Beige                 Style
       .     ...                            ...

…where the style templates are Analysis, Astronomy, Banker, etc.

To see the effect of changing the style template, first copy the following code into a SAS session, run it, and look at the resulting RTF file:

options nodate nonumber;

ods Listing close;
ods RTF  file="c:\temp\Class_Report.rtf”;

    proc print data=sashelp.class  noobs n;
      title1 "Report of Class Weight/Height Study";
    run;

ods RTF close;
ods Listing;

Not bad.  No surprises there, right?

Now, run this code that has the Astronomy style template specified:

options nodate nonumber;

ods Listing close;
ods RTF  file="c:\temp\Class_Report.rtf" style=astronomy;

    proc print data=sashelp.class  noobs n;
      title1 "Report of Class Weight/Height Study";
    run;

ods RTF close;
ods Listing;

Very nice departure from the default, isn’t it?  Well, you have 56 more styles (…because one style is the Default; which you previously used) to try, so I am sure that you will find one that is just perfect for your team and your client!

It’s nice to see a bit of color in your reports, isn’t it?

Best of luck in all your SAS endeavors!


---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 

The hack above is an excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers

Tuesday, October 17, 2017

Hack 6.4 Inserting the SAS Date and Time into an RTF Document



SAS Programming Professionals,

Did you know that you can insert the standard SAS date and time into a new RTF document in place of the default RTF specification that inserts the printing date and time?

This is a bit hard to visualize, but stick with me; it’s worth it! 

If you were to submit the follow simple program at 8:00am this morning:

ods rtf file="rtfdate2.rtf";

proc print data=sashelp.class;
run;

ods rtf close;

…you would create an RTF document that would have the date/time embedded as a header in the upper right hand side.  If you were to open that file at 11:00am this morning, the header would read:

11:00 Monday, December 12, 2015  1

…even thought it was actually created at 8:00am this morning.  If you were to print the document at 11:30 this morning, the header on the printed page would read:

11:30 Monday, December 12, 2015  1

…even though it was actually created at 8:00am this morning and you opened the file at 11:00am this morning. 

Now, what’s wrong with this picture?  Well, nothing if you want the RTF default header date/time in effect.  However, if you want to document the date/time this document was actually created, then code the SASDATE option in the ODS statement.  Here is an example using the same program as before:

ods rtf file="sasdate.rtf" sasdate;

proc print data=sashelp.class;
run;

ods rtf close ;

If you were to submit that at 8:00am this morning, then whenever you open it up, you will see the following header:

8:00 Monday, December 12, 2015  1

Similarly, whenever you print the document, that will be the header in the hard copy.  This will happen each and every time that you open the file and that you print the file.

So, the SASDATE option on the ODS FILE= statement “freezes” the date/time the RTF document was created.  Nine times out of ten, that is exactly the behavior that I want!  And you?

Best of luck in all your SAS endeavors!


---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 

The hack above is an excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers