Encoding: 213 TEXT
X-Mailer: Microsoft Mail V3.0 (beta-2)
Newsgroups: bit.listserv.sas-l
Date:         Tue, 18 Aug 1992 14:07:00 EST
Reply-To:     SPJ1@CEHIEC1.EM.CDC.GOV
From:         SPJ1@CEHIEC1.EM.CDC.GOV
Subject:      Documenting SAS Data Sets (220 lines)
Comments: To: SAS-L%UGA.BITNET@UGA.CC.UGA.EDU

Summary          Program to Document SAS Data Sets.
Rlse/Pltfm       MVS 6.07 and probably other platforms.
Name             Steve James
BITNET Address   SPJ1%UGA.BITNET@UGA.CC.UGA.EDU
INTERNET Address SPJ1@CEHIEC1.EM.CDC.GOV
Real address     Centers for Disease Control
                 1600 Clifton Road NE, Mailstop F36
                 Atlanta, GA  30333
                 (404) 488-4656

---------------------------------------------------------------------------

    Several weeks ago someone sent a request asking for a SAS program to help
in documenting SAS programs by providing a cross-reference of variable names
and their use.  That request reminded me of a program that I wrote awhile ago
that may be of some interest to SAS-L.  My program includes the formatted
value of each variable along with the information provided with PROC
CONTENTS.  An example would be:

Variable Name  Type  Length   Label              Format    Formatted Values

SEX            Num     2     Gender of person    sexfmt    (1)Male
                                                           (2)Female
                                                           (9)Unknown/Missing

    I find this program useful because I don't have to run a separate
procedure to find out what possible values the data has.  The program can put
the unformatted value in parentheses with the formatted value (eg '(1)Yes' as
opposed to 'Yes') if it's not already there; there is code commented
out towards the end of the program to do this.  And it will print out a
limited number of formatted values (arbitrarily set to 10 currently) for
formats that may have a large number of separate values, such as state or
country.  Currently it's set up to print out on 132 columns but can be
modified to print in 80 columns (I'll leave that for you).  Hope people find
it useful.

Steve James, Centers for Disease Control

*-------------------------------------------------------------------;
* This program creates a documentation report by combining the      ;
* outputs of a PROC CONTENTS with a PROC FORMAT.  To run, first     ;
* modify the page size and other options to suit your taste and     ;
* installation.  Then modify the data in the %LET statements to     ;
* reflect what data set that you want reported.  Note: if there are ;
* more values to print out for a format than assigned to MAXLABEL,  ;
* the last value printed will be '...and more...'.                  ;
*-------------------------------------------------------------------;

OPTIONS PAGESIZE=96 NODATE CHARCODE;

%LET MAXLABEL = 10 ;               * SET MAXIMUM NUMBER OF VALUES TO;
                                   * PRINT OUT FOR EACH FORMAT ;

%LET FMTLIB   = LIBRARY ;          * IDENTIFY LIBREF OF FORMAT LIBRARY ;

%LET LIBRARY = NF00.FALLS.FORMATS; * IDENTIFY FORMAT LIBRARY ;

%LET DSN = NF00.FALLS.FINALSAS ;   * IDENTIFY SAS DATA LIBRARY ;

%LET MEMBER = FALLS    ;           * IDENTIFY DATA SET NAME ;

LIBNAME DATA "&DSN" disp=shr;
LIBNAME LIBRARY "&LIBRARY" DISP=SHR ;

TITLE 'DOCUMENTATION FOR SAFE SYSTEM' ;

proc format ;
  value vartype 1='Num' 2='Char' ;
  run;

*-------------------------------------------------------------------;
* Now create the data set that contains the formats.  The goal is   ;
* to create a data set where each observation contains the format   ;
* name, as well all the values that it can contain.  This is done   ;
* by massaging the output of a PROC FORMAT.                         ;
*-------------------------------------------------------------------;

PROC FORMAT LIBRARY=LIBRARY
     CNTLOUT=FMTOUT(RENAME=(FMTNAME=FORMAT LABEL=FMTLABEL TYPE=FTYPE));

*-------------------------------------------------------------------;
* Create a data set with a list of all the variables and format     ;
* names.                                                            ;
*-------------------------------------------------------------------;

PROC CONTENTS DATA=DATA.&MEMBER NOPRINT OUT=VARS ;

DATA VARS ;
  SET VARS ;
  IF TYPE EQ 2 THEN FORMAT = '$' ?/?/ FORMAT ;
  RUN;

DATA NUMVARS(KEEP=MEMNAME NUMVARS) ;
  SET VARS END=LASTOB ;
  IF LASTOB
  THEN DO ;
       NUMVARS = _N_ ;
       OUTPUT ;
       END ;

*-------------------------------------------------------------------;
* Create a data set containing the format name and each associated  ;
* value label on one observation.                                   ;
*-------------------------------------------------------------------;

DATA FORMATS ;
  LENGTH LABEL1-LABEL&MAXLABEL $25. ;
  RETAIN LABEL1-LABEL&MAXLABEL ;
  ARRAY LABELS{*} LABEL1-LABEL&MAXLABEL ;
  SET FMTOUT ;
  BY FORMAT ;
  IF FIRST.FORMAT
  THEN DO ;
       I=1 ;
       DO J=1 TO &MAXLABEL ;
         LABELS{J}= ' ' ;
       END ;
       END ;
  ELSE I+1 ;

  IF I LT &MAXLABEL OR (I EQ &MAXLABEL AND LAST.FORMAT)
  THEN LABELS{I} = FMTLABEL ;
  ELSE LABELS{&MAXLABEL} = '...and more...' ;

*----------------------------------------------------------------;
*  if the value of your format label is not a part of the label  ;
*  eg. label is YES rather than (1)YES, try using the following. ;
*----------------------------------------------------------------;
  /*
  IF I LT &MAXLABEL OR (I EQ &MAXLABEL AND LAST.FORMAT)
  THEN DO ;
       IF START EQ END
       THEN LABELS{I} = '(' ?/?/ LEFT(TRIM(START)) ?/?/ ')' ?/?/ FMTLABEL ;
       ELSE LABELS{I} = '(' ?/?/ LEFT(TRIM(START)) ?/?/ '-'
                            ?/?/ LEFT(TRIM(END))   ?/?/ ')' ?/?/ FMTLABEL ;

      END ;
  */

  IF LAST.FORMAT
  THEN DO ;
       OUTPUT ;
       END ;
  RUN;

*---------------------------------------------------------------------;
* Combine the two data sets by format name.                           ;
*---------------------------------------------------------------------;

PROC SORT DATA=VARS ;
  BY FORMAT ;
  RUN;

DATA BOTH ;
  MERGE FORMATS VARS(IN=V) ;
  BY FORMAT ;
  IF V ;
  RUN;

PROC SORT DATA=BOTH ;
  BY NAME ;
  RUN;

*---------------------------------------------------------------------;
* Now you have a data set with the variable names, format name, and   ;
* the label associated with each possible value of the variable (up   ;
* to a defined limit).  So print it out.                              ;
*---------------------------------------------------------------------;

DATA _NULL_ ;
  MERGE BOTH NUMVARS ;
  BY MEMNAME ;
  ARRAY LABELS{*} LABEL1-LABEL&MAXLABEL ;
  RETAIN COL1 10 COL2 21 COL3 27 COL4 43 COL5 84 COL6 107 ;
  DATA1=COL1 ; DATA2=COL2 ; DATA3=COL3+2 ; DATA4=COL4-6 ;
  DATA5=COL5 ; DATA6=COL6-10 ;
  FILE PRINT HEADER=H LINESLEFT=LL ;
  IF LL LE &MAXLABEL THEN PUT _PAGE_ ;
  PUT @DATA1 NAME  $8.  @DATA2 TYPE VARTYPE. @DATA3 LENGTH 2.
      @DATA4 LABEL $40. @DATA5 FORMAT $8. @DATA6 LABEL1 $25. ;
  DO I = 2 TO &MAXLABEL ;
    IF LABELS{I} NE ' ' THEN PUT @DATA6 LABELS{I} ;
  END ;
  IF LABELS{2} EQ ' ' THEN PUT;
  PUT ;
  RETURN ;
H:

  IF _N_ EQ 1
  THEN DO ;
       LENGTH NUMOBS $7. TODAY 3. ;
       NUMOBS = LEFT(PUT(NOBS,COMMA7.)) ;
       TODAY=TODAY() ;
       PUT //  @50 "DATA SET NAME " @80 "&DSN"/
               @50 "MEMBER NAME   " @80 "&MEMBER" /
               @50 "NUMBER OF VARIABLES"  @80 NUMVARS  /
               @50 "NUMBER OF OBSERVATIONS " @80 NUMOBS $7. /
               @50 "DATE OF REPORT "  @80 TODAY MMDDYY8. // ;
       END ;

  COL6A = COL6 - 1 ;
  PUT // @COL6A 'FORMATTED'/
         @COL1 'VARIABLE' @COL2 'TYPE' @COL3 'LENGTH' @COL4 'LABEL'
         @COL5 'FORMAT' @COL6 'VALUES'
         // ;
  RETURN ;
Comments: Gated by NETNEWS@AUVM.AMERICAN.EDU