Friday 18 September 2009

NOTE: Global Statements

I occasionally see confusion caused by SAS's global statements so here's a clarification. A typical example of the confusion is a programmer struggling to get libname statements to work properly within conditional logic with a DATA step:

%let env = DEV;
data _null_;
  if &env eq DEV then libname data "c:\mydata\dev";
  else libname data "h:\prod\finance";
run;

When the example  code is run it always allocates the "data" libname to the production data library, never to the development library.

The reason is that the libname statement is a global statement. The SAS Language Reference: Concepts manual (SAS Language Elements section, see v9doc.sas.com) explains that a SAS statement is a series of items that may include keywords, SAS names, special characters, and operators. All SAS statements end with a semicolon. A SAS statement either requests SAS to perform an operation or gives information to the system. There are two kinds of SAS statements:
  • those that are used in DATA step programming ("executable statements")
  • those that are global in scope and can be used anywhere in a SAS program ("global statements")
Global statements generally provide information to SAS, request information or data, move between different modes of execution, or set values for system options. You can use global statements anywhere in a SAS program. Most importantly, from the point of view of this post's topic, global statements are not executable; they take effect as soon as SAS compiles program statements.

So, in our example code above, it executes both libname statements every time the code is run, and the latter libname statement overides the library set by the first statement.

There's more than one way to resolve the problem in the example code. One method would be to use conditional macro code:

%macro AllocDataLib(env=);
  %if &env eq DEV %then libname data "c:\mydata\dev";
  %else libname data "h:\prod\finance";
%mend AllocDataLib;

%AllocDataLib(env=DEV);

Another solution would be to use the libname function instead of the statement:

%let env = DEV;
data _null_;
  if &env eq DEV then rc=libname("data","c:\mydata\dev");
  else rc=libname("data","h:\prod\finance");
  if rc ne 0 then put "DISASTER: Failed to allocate library";
run;

There's always more than one way to skin the SAS cat, isn't there?