Monday, January 16, 2017

Hack 4.8 Putting Your SAS Programs to Sleep


SAS Programming Professionals,

Did you know that you can actually put your SAS programs to sleep?

The SLEEP function suspends execution of your SAS program (puts it to sleep) for the duration of time that you specify in the function.  This function comes in handy when you need to programmatically pause your SAS programs for various reasons.  One such reason is to wait for an asynchronous system event to occur before your SAS program continues.  For example, if you use an X statement to invoke an operating system command, you could put your program to SLEEP for the duration that it takes for that command to complete.

The general form of the SLEEP function is:  Q = SLEEP(N); …where:

·        Q = any SAS variable

·        N = the number of seconds to wait.  The maximum is 46 days!  See the documentation if you want to specify other intervals, such as micro-seconds.

Here is an example of the SLEEP function in action:

options noxwait noxsync xmin;

x '"C:\Program Files\Microsoft Office\Office11\excel.exe"';

data _null_;
  x=sleep(10);
run;

filename comma1 dde 'excel|system';

data _null_;
 file comma1;
 put '[open("D:\MCR\t_excel.xls")]';
run;

data _null_;
  x=sleep(10);
run;

…Other SAS code to populate the Excel spreadsheet…

The overall thrust of this example is to use DDE to open and populate an Excel spreadsheet from a SAS program.  First, we use the SAS X statement to send a command to Windows to open Excel.  Secondly, we put our program to sleep for 10 seconds in a DATA _NULL_ step to give Windows enough time to complete opening Excel.  Next, the FILENAME statement sets up our DDE “environment” and the second DATA _NULL_ creates our spreadsheet in the opened Excel program.  Then, we put our SAS program to sleep a second time to give Excel enough time to create the t_excel.xls spreadsheet in the opened Excel program in the aforementioned DATA _NULL_ step.

If you are tired of having your programs fail due to SAS-generated asynchronous tasks not completing on time, consider using the SLEEP function!

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, January 9, 2017

Hack 4.7 Increasing the Accuracy of Age Calculations with the YRDIF Function


SAS Programming Professionals,

Did you know that the YRDIF function can increase the accuracy of your age calculations?

The YRDIF function returns the number of years between two dates.  So, it can be useful in cases where you are looking for age, years in a study, duration of dosage, etc.  The format of the YRDIF function is:

               YRDIF(start-date, end-date, basis)

…where basis describes how SAS should calculate the difference between dates.  The most common basis is “ACT/ACT”, which specifies that SAS is to calculate YRDIF as the number of days that fall in 365-day years divided by 365 plus the number of days that fall in 366-day years divided by 366.  Here is an example:

data mybirthday;

     my_age_in_years = yrdif("27APR1975"d,today(),"ACT/ACT");

     label my_age_in_years = "My Current Age";

run;

proc print noobs label data=mybirthday;
run;

In the example, we determine the difference between my birth date and today’s date.  I entered a date literal for start-date and the TODAY() function for end- date, but I could have easily used two variables containing date values, instead.  The SAS listing looks like this:

My Current Age

   39.1534

Of course the year calculation is only as accurate as the information you feed into the YRDIF function.  If you are curious about other possible values for basis, look up the YRDIF function in the SAS Online Documentation on support.sas.com.

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, January 3, 2017

Hack 4.6 Determining The Dates of Major Holidays with the HOLIDAY Function


SAS Programming Professionals,

Did you know that the HOLIDAY function allows you to determine the date of major US and Canadian holidays? 

You simply supply the HOLIDAY function with the holiday keyword and the year, and it will return the SAS date value.  The syntax looks like this:

               HOLIDAY('holiday',year)

Here is an example that computes three holidays for the next ten years:

data future_holidays;

label year = "Year"
      mothersday= "Mothers Day"
      presidentsday = "Presidents Day"
      victoriaday = "Victoria Day"
      ;
format mothersday presidentsday victoriaday worddate.;

do year = 2015 to 2025 by 1;

mothersday = holiday("MOTHERS",year);
presidentsday=holiday("USPRESIDENTS",year);
victoriaday=holiday("VICTORIA",year);
output;
end;

run;

proc print noobs label;
run;

There are currently twenty-two holiday keywords for the HOLIDAY function.  You can read more about the HOLIDAY function, including all of the available holiday keywords, in the SAS online documentation on the support.sas.com web site.
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, December 19, 2016

Hack 4.5 Determining How Large an Integer You Can Store in a Numeric Variable

SAS Programming Professionals,

Did you know that the CONSTANT function can help you to determine how large an integer you can store in a numeric variable with a given number of bytes? 

This can be helpful when you are working at slimming-down SAS data sets by reducing the number of bytes for numeric variables.  If you know—and know for sure—the largest value that will be stored in that variable, and that you will only be using it to store integers, then you can set its byte-size accordingly.

Here is how you can use the CONSTANT function with the EXACTINT constant:

data _null_;

do i = 2 to 8 by 1;

exactint = constant('EXACTINT',i);

put i exactint;

end;

run;

The PUT statement produces the following:

2 32
3 8192
4 2097152
5 536870912
6 137438953472
7 3.5184372E13
8 9.0071993E15

So, a numeric variable created with a length of 4 will allow me to store integers up to a value of 2,097,152. Note that these results may vary depending on the platform you are using to run SAS.

Two other CONSTANT function constants that are worth exploring are:  BIG and SMALL.

·        BIG = constant(‘BIG’); - Returns the largest double-precision floating-point number (8-bytes) that can be represented on your computer.

·        SMALL = constant(‘SMALL’); - Returns the smallest double-precision floating-point number (8-bytes) that can be represented on your computer.

Check out the CONSTANT function for more insights on how numbers are handled on your computing platform in the online documentation at support.sas.com.  Then, see if it makes sense to slim down some of your observations by right-sizing your numeric variables.

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
http://www.amazon.com/Michael-A.-Raithel/e/B001K8GG90/ref=ntt_dp_epwbk_0

Monday, December 12, 2016

It Only Hurts When I Hit ENTER


SAS Programming Professionals,

If you want to take a break from the serious side of programming, then check out my new book:  It Only Hurts When I Hit <ENTER>

My new book is available on Amazon.com as a print edition:  http://tinyurl.com/z8bzx2e
…or a Kindle e-book:  http://tinyurl.com/zypgqa7
Best of luck in all of your SAS endeavors!

----MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Amazon Author Page:
http://www.amazon.com/Michael-A.-Raithel/e/B001K8GG90/ref=ntt_dp_epwbk_0

Monday, December 5, 2016

Hack 4.4 Creating SAS Date Variables with the MDY Function

SAS Programming Professionals,

Did you know that you can create a SAS date variable from a set of month, date, and year variables?

The MDY function creates a SAS date value from month, day, and year values.  It can be helpful when you process data where the unfortunate decision was made to collect month, day, and year in separate variables.  Here  is an example of the MDY function:

data newdate;

format birthdate worddate.;

birth_day = 27;
birth_month = 4;
birth_year = 1975;

birthdate = mdy(birth_month, birth_day, birth_year);

yearsold = year(today()) - year(birthdate);

run;

proc print noobs;
run;

In the example, we employ the MDY function to create a SAS date variable, BIRTHDATE, from separate birth_month, birth_day, and birth_year variables.  Then, we use BIRTHDATE to compute the subject’s age.

A derivative of this simple technique can be used in cases where you get the month and year of a date, but for privacy’s sake, you do not get the day.  You can hardcode a given day value—say 15 because it is the middle of most months—and create a reasonable date that you can use in calculations.  For example, consider the DATA step above without the day variable:

data newdate;

format birthdate worddate.;

birth_month = 4;
birth_year = 1975;

birthdate = mdy(birth_month, 15, birth_year);

yearsold = year(today()) - year(birthdate);

run;

In this example, we hard-coded 15 in the MDY function so that we could compute a valid date for BIRTHDATE.  We could have just as easily used a 1 or a 28 to signify the first day of the month, or a day near the end of the month.  Which is the better way to go?  It is your manager’s sage choice, of course!

Best of luck in all your SAS endeavors!

----MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)

Excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers
http://www.amazon.com/Michael-A.-Raithel/e/B001K8GG90/ref=ntt_dp_epwbk_0

Monday, November 28, 2016

Hack 4.3 Computing Smallest and Largest Value for Variables in An Observation

SAS Programing Professionals,

Did you know that you can easily compute the smallest or the largest value for a group of variables within an observation in a DATA step?

The SMALLEST and LARGEST functions return the smallest and largest value, respectively, for the group of values that you specify.  You can also have these functions return the second from smallest (or largest) value, third from smallest (or largest) value, fourth from smallest (or largest) value, and so on.  The form of these functions is:

SMALLEST(k, value-1<,value-2,…>)

LARGEST(k, value-1<,value-2,…>)

…where k = is a numeric constant, variable, or expression that specifies which value to return.  And, value-1 (value-2, etc.) specifies the value of a numeric constant, variable, or expression to be processed.

Here is an example:

options nodate nonumber;

data class(keep=oldest youngest agerange);

array ages{19} ages1 - ages19;

do i = 1 to totobs;

set sashelp.class nobs=totobs;

ages{i} = age;

end;

label youngest = "Age of Youngest Participant"
      oldest   = "Age of Oldest Participant"
      agerange = "Range of Participant Ages"
      ;

youngest = smallest(1,of ages1-ages19);
oldest   = largest(1,of ages1-ages19);
agerange = oldest - youngest;

run;

proc print noobs data=class label;
run;

In this example, we create an array (AGES) to contain the ages for all participants in our study data set.  We use the DO loop to iterate through the CLASS data set and load the ages of the participants into the array.  Then, we use the SMALLEST and the LARGEST functions to return the smallest and largest age values stored in the array.  We also calculate the range of ages.

If we had wanted the next to smallest age value, we would have coded:

 youngest = smallest(2,of ages1-ages19);

Get the picture?

If you rolled your eyes when reviewing this contrived example, think how powerful these functions are when you have a flattened patient file of admission/discharge dates.  You can quickly and easily compute the earliest or latest admission dates as well as the earliest or latest discharge dates.  These functions are in the top compartment of my own SAS tips-and-techniques toolbox!

Best of luck in all your SAS endeavors!

----MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)

Excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers
http://www.amazon.com/Michael-A.-Raithel/e/B001K8GG90/ref=ntt_dp_epwbk_0