Showing posts with label programming language - SAS. Show all posts
Showing posts with label programming language - SAS. Show all posts

Monday, May 4, 2009

Different Methods to Specify SAS Config File

There are different methods to config SAS in unix environment. First of all, for every installatoin, there is a config file stored in the installation directory alongside with the SAS executable file (i.e. the sasroot directory). This file is named config.sas in version-6, sasv8.cfg in version-8 and sasv9.cfg in version-9. This config file is effective for all users in this machine using this SAS. For example, this line in the config file can let all users to share the SAS working directory:
-work '/production/global/sas_working_directory' ;

However, if there is a config file in the $HOME directory e.g.
/home/alvin/config.sas
, SAS will use this $HOME config file instead.

Using this method, each programmer can has his/her own SAS configuration setting, e.g. using his own very large working directory instead of the global one :
-work '/my_large_filesystem/sas_working_directory' ;

But, when there are some other parameters changes e.g.
-sortsize 32M
and the program is rolled out to production, how can you ensure that the config file is also adjusted to be similar to the programmer's own config file (i.e. to -sortsize 32M) ? The change is ONLY in the programmer's config file in the programmer's $HOME directory. This is a serious drawback. (Actually, the change is not reflected in system test and user acceptance test either.)

Also, when upgrading from SAS version-6 to version-8, the name of the config file is changed from config.sas to sasv8.cfg. All user's config file under $HOME directory will be affected. Similarly when upgrading from version-8 to version-9.

Starting from version-8, we can also use environment variables SASV8_OPTIONS and SASV8_CONFIG to specify the config files. Using this method, it is more easy for all team members of a department to SHARE a common config file. For example:
export SASV8_OPTIONS='-config /company/department/common/sasv8.cfg' sas my_program.sas
or
export SASV8_CONFIG=/company/department/common/sasv8.cfg sas my_program.sas

These environmental variables can be specified in a common profile file. All team members has to call this departmental common profile file to make it effective for the login sessoin.

Another method is to specify the config file as command line option when calling the SAS executable. The advantage of using this method is the capability of specifing different configuration under different development phases. For example, in development phase, we can use a development configuration file like this :
export MYSASCONFIGFILE=/project/dvt/sasv8.cfg sas -config $MYSASCONFIGFILE my_program.sas
Then, during system test, we can do this :
export MYSASCONFIGFILE=/project/syt/sasv8.cfg sas -config $MYSASCONFIGFILE my_program.sas
During user acceptance test, we can do this :
export MYSASCONFIGFILE=/project/uat/sasv8.cfg sas -config $MYSASCONFIGFILE my_program.sas
Using this method, we can adjust the parameters (e.g. the working directory) in different development phases. In case some parameters needed to be adjusted, the UAT version of sasv8.cfg file can also be check-in / check-out to rollout to production.

By the way, since SAS version-8 and versoin-9 has some more complicated ways to specify the config file please refer here for the details for version-8 and this for version-9.

In short, before using SAS for any project, the first thing is to define the way of using the config file. It is better to use a systematic approach, rather than an ad-hoc way (e.g. the $HOME config file method).


Thursday, April 30, 2009

SAS Operator for Not-Equal

For many programmers, Pascal is the first programming language learnt. In Pascal, the operator <> means not equal.
SAS also has such a <> operator. But, this <> operator does NOT mean not-equal, it means MAX. It simply return the maximum of the 2 values under comparsion.
Actually, the offical not-equal operator in SAS are :
  1. ne
  2. ^=
  3. ¬=
  4. ~=
This is the link for SAS version-8 operators for your reference.
Frankly speaking, this quite odd usage of the <> operator in SAS will easily make some beginners fall into the trap of assuming <> to stand for not-equal. In SAS version-8, you can change the warning level to let the interpreter to issue a warning message when it sees a <> operator to alert the programmer that it is a MAX operator.
Since in real life the usage of getting the maximum using the <> operator is quite rare, my previous working experience is to use a pre-compiler alike construct to scan all SAS program to forbid using the <> operator. This can avoid falling into the trap of mistakenly using it to mean not-equal for everyone in the department. Actually, in SAS, there is a max() function which perform SIMILAR processing as the <> operator.

Substring in SAS

In many programming languages, there is a substr() function which will extract a portion of a string. SAS also has such a function. But, in SAS the substr() function is a little bit complicated.

In SAS version-8, if you put the substr() function on the left of the = sign, the substr() is actually a procedure to substitute string. It will replace a portion of the argument string with values at the right of the = sign. This link shows the version-8 syntax and here is the version-9 syntax.

If, however, the substr() function is put at the right of the = sign, the behavior of the substr() function is the normal sub-string function as expected by many ones. It will return a portion of the argument string. This link is the version-8 syntax and here is the version-9 syntax.

In SAS version-8, there is another function called kstrstrb(). Its function is to extract a substring in terms of byte. The DBCS version of this function is called ksubstr(). SAS version-9 also has these two functions.

In short, putting the substr() function on the LHS or RHS of the = sign will have very different behaviours. Putting it on the LHS will alter the argument string, just like passing parameter by reference. Putting it on the RHS is a function call with parameters passed by value and the argument string will NOT be altered.

By the way, when writing SAS macro, there are %substr() and %qsubstr() macro functions doing similar substring extraction processing.




Wednesday, December 3, 2008

A Trap in SAS Macro Programming

When using SAS macro, beginners will easily fall into this trap if they do not understand that SAS macro is somewhat just a text substitution.

Look at this example. There is a database of 10 persons created using this program :
option mprint source2 noovp ;

data person ;
     length name  $20. ;
     length sex   $1.  ;

     name= 'Angelina'  ; sex= 'F' ; output ;
     name= 'Babara'    ; sex= 'F' ; output ;
     name= 'Clara'     ; sex= 'F' ; output ;
     name= 'Diana'     ; sex= 'F' ; output ;
     name= 'Eva'       ; sex= 'F' ; output ;
     name= 'Frankie'   ; sex= 'M' ; output ;
     name= 'George'    ; sex= 'M' ; output ;
     name= 'Henry'     ; sex= 'M' ; output ;
     name= 'Ivan'      ; sex= 'M' ; output ;
     name= 'John'      ; sex= 'M' ; output ;
run;
After execution, the table person contains these records:
Obs    name        sex

  1    Angelina     F
  2    Babara       F
  3    Clara        F
  4    Diana        F
  5    Eva          F
  6    Frankie      M
  7    George       M
  8    Henry        M
  9    Ivan         M
 10    John         M

Then, three more fields (initial, wear_tie and wear_bra) are added to the table. Records of male and female are with different initialization. The initial is 'Mr.' for all males and 'Miss' for all females. All male records will have wear_tie=Y and wear_bra=N whereas all female records are just the opposite (i.e. wear_tie=N and wear_bra=Y).

For the first thought, here is the program using macro for the initialization :
%macro init_male ;
       initial=  'Mr.' ;
       wear_tie= 'Y'   ;
       wear_bra= 'N'   ;
%mend;

%macro init_female ;
       initial=  'Miss' ;
       wear_tie= 'N'    ;
       wear_bra= 'Y'    ;
%mend;

data person_1 ;
     set person ;
     length initial  $4. 
            wear_tie $1.
            wear_bra $1.     
            ;
     if sex = 'M' then %init_male   ;
     if sex = 'F' then %init_female ;
run;

proc print data=person_1 ;
quit;

The program design seems very straight forward. The macro init_male is for male record initialization and the macro init_female is for all female record initialization.

But, the outcome is not what we expected. Here is the output table person_1 :
Obs    name        sex    initial   wear_tie   wear_bra

  1    Angelina     F      Miss        N          Y
  2    Babara       F      Miss        N          Y
  3    Clara        F      Miss        N          Y
  4    Diana        F      Miss        N          Y
  5    Eva          F      Miss        N          Y
  6    Frankie      M      Mr.         N          Y
  7    George       M      Mr.         N          Y
  8    Henry        M      Mr.         N          Y
  9    Ivan         M      Mr.         N          Y
 10    John         M      Mr.         N          Y
The fields wear_tie and wear_bra are initialized incorrectly for all male records. The male records should have wear_tie=Y and wear_bra=N, but they are not.
How about re-arranging the 2 macro lines like this:
data person_2 ;
     set person ;
     length initial  $4. 
            wear_tie $1.
            wear_bra $1.     
            ;
     if sex = 'F' then %init_female ;
     if sex = 'M' then %init_male   ;
run;

proc print data=person_2 ;
quit;
Now, the output table person_2 looks:
Obs    name        sex    initial   wear_tie   wear_bra

  1    Angelina     F      Miss        Y          N
  2    Babara       F      Miss        Y          N
  3    Clara        F      Miss        Y          N
  4    Diana        F      Miss        Y          N
  5    Eva          F      Miss        Y          N
  6    Frankie      M      Mr.         Y          N
  7    George       M      Mr.         Y          N
  8    Henry        M      Mr.         Y          N
  9    Ivan         M      Mr.         Y          N
 10    John         M      Mr.         Y          N
This time, the result is wrong for all female records.

Actually, both programs have fall into the trap of SAS macro. The correct program should be written like this :
data person_3 ;
     set person ;
     length initial    $4. 
            wear_tie $1.
            wear_bra   $1.     
            ;
     if sex = 'M' then do; %init_male   ; end;
     if sex = 'F' then do; %init_female ; end;
run;

proc print data=person_3 ;
quit;
Then, the table person_3 will have these records :
Obs    name        sex    initial   wear_tie   wear_bra

  1    Angelina     F      Miss        N          Y
  2    Babara       F      Miss        N          Y
  3    Clara        F      Miss        N          Y
  4    Diana        F      Miss        N          Y
  5    Eva          F      Miss        N          Y
  6    Frankie      M      Mr.         Y          N
  7    George       M      Mr.         Y          N
  8    Henry        M      Mr.         Y          N
  9    Ivan         M      Mr.         Y          N
 10    John         M      Mr.         Y          N
The output result is exactly what we want.

Then, actually what is wrong with the programs for person_1 and person_2 ? This is due to SAS macro substitution. SAS will actually [ substitute ] the macro statements into the program. If you do not understand this [ substitution ] activity, you will fall into this trap.

So, for the program fragment for person_1 :
data person_1 ;
     set person ;
     length initial  $4. 
            wear_tie $1.
            wear_bra $1.     
            ;
     if sex = 'M' then %init_male   ;
     if sex = 'F' then %init_female ;
run;
, after substitution, the program fragment will become :
data person_1 ;
     set person ;
     length initial  $4. 
            wear_tie $1.
            wear_bra $1.     
            ;
     if sex = 'M' then initial= 'Mr.' ;
     wear_tie= 'Y' ;
     wear_bra= 'N' ;
     if sex = 'F' then initial= 'Miss' ;
     wear_tie= 'N' ;
     wear_bra= 'Y' ;
run;
(I have re-indent the coding for easy reading. The actual substitution text is quite difficult to read.)

As one can see, after substitution, only the [ initial ] field will work as what we expected. The fields wear_tie and wear_bra will be set regardless of the sex field. At the last 2 lines of the program, all the wear_tie will be N and wear_bra will be Y regardless of male or female record. Thus, the person_1 will have this not-expected output.

However, when calling a macro inside a pair of do-end statements, these 2 lines of coding :
if sex = 'M' then do; %init_male   ; end;
if sex = 'F' then do; %init_female ; end;
, after substitution, will become :
if sex = 'M' then do;
                    initial=  'Mr.' ;
                    wear_tie= 'Y'   ;
                    wear_bra= 'N'   ;
                  end;
if sex = 'F' then do;
                    initial=  'Miss' ;
                    wear_tie= 'N'    ;
                    wear_bra= 'Y'    ;
                  end;
(Again, I have re-indent the coding for easy reading.)

This is what we expected.

To avoid falling into this trap, always remember that SAS macro can be treated as text substitution.


Alvin SIU
2008-12-03
Copyright/Licence Information:
All information and coding in this article is offered at no charge for NON-COMMERCIAL PERSONAL USE only.
This blog and the coding is copyright.
Reproduction of this blog and its coding in whole or in part in paper or digitally or in any other forms without the explicit written permission of the author is strictly prohibited.

Disclaimer:
All information in this article is distributed "as is" and is UNSUPPORTED.
NO WARRANTY of any kind is expressed or implied.
You use AT YOUR OWN RISK.
The author will not be liable for any data loss, damages, and loss of profits or any other kind of tangible or intangible loss while using or misusing wholly or partly of the information.

Friday, November 21, 2008

Describe a SAS view

For SAS version 6.12 in unix, files with extension ssv01 are SAS views. For SAS version 8 and 9, the file extension is changed to sas7bvew (this also apply for Windows).
In my previous company, there are at least 2 types of SAS views. I will called one type as data step views, because the view is generated by a data step statement. Another type is referred as SQL-view which is actually a SAS view on DB2 table generated using a [ proc sql ] statement.
Both types of SAS view will have the same file extension. Therefore, by just looking at the file extension, you cannot know which type of view one is using.
Starting from SAS version 8 in AIX, the view generation source code is also included inside the sas7bvew file. Therefore, you can [ describe ] the sas7bvew file to find out how the view is generated.
But, you have to use different programming statements to [ describe ] the 2 types of views.
For data step views, the coding is :
data view=myLib.myView ; describe ; run;
For SQL-view, the coding is :
proc sql ; describe view myLib.myView ; quit;
On looking at the myView.sas7bvew file, how do you know which one of the two codings to be used ? This depends on whether there is some pre-defined file name naming standard in your company. If there is such a standard, you can tell by the file name. If not, simply use trial and error.

Alvin SIU
2018-11-21
Last Updated: 2020-04-04

Copyright/Licence Information:
All information and coding in this article is offered at no charge for NON-COMMERCIAL PERSONAL USE only.

This blog and the coding is copyright.
Reproduction of this blog and its coding in whole or in part in any form without the explicit written permission of the author is strictly prohibited.

Disclaimer:
All information in this article is distributed "as is" and is UNSUPPORTED.
NO WARRANTY of any kind is expressed or implied.
You use AT YOUR OWN RISK.
The author will not be liable for any data loss, damages, and loss of profits or any other kind of tangible or intangible loss while using or misusing wholly or partly of the information.

Duplicate Open Current Folder in a New Window

Sometimes after I opened a folder in Win7, I would like to duplicate open the same folder again in another explorer window. Then, I can ope...