Macro CallText

From sasCommunity
Jump to: navigation, search

Companion: Macro_CallMacr

Contents

Programs

CallText demo nrstr and unquote

This program shows the trick within calltext: provide the parameter value in macro function nrstr and return it -- resolve it -- using the macro function unquote.

*name       : calltext-demo-macro-statements.sas;
*description: demonstration of nrstr and unquote;
*purpose    : test suite for calltext;
 
%Let Sex = ?;
%Let Count = 0;
%Let Percent = 0;
%Let Text = %nrstr(tokens: Sex: &Sex Count: &Count Percent: &Percent);
%Let Sex = F;
%Let Count = 9;
%Let Percent = 47;
%Put note: %unquote(
&Text.
);
%Let Sex = M;
%Let Count = 10;
%Let Percent = 52;
%Put note: %unquote(
&Text.
);
%Put;


Log:

note: tokens: Sex: F Count: 9 Percent: 47
15         %Let Sex = M;
16         %Let Count = 10;
17         %Let Percent = 52;
18         %Put note: %unquote(
19         &Text.
20         );
note: tokens: Sex: M Count: 10 Percent: 52

CallText

 /*       Name: calltext.sas
 /*   location: <UNC>\SAS-site\macros
        Author: Ronald J. Fehd 2012
                -------------------------------------------------------
Summary       : description  : call text with specified
                               values in data set as parameters
                purpose      : provide generic method to call text
                               using list==control data set of parms
                -------------------------------------------------------
Contexts      : program group: list processing token generator
                program  type: function
                SAS      type: macro assignment statement generator
                uses routines: n/a
                -------------------------------------------------------
Specifications: input  : required: Data, Text
                         optional: Hex16
                process: assemble macro variable assignment(s), call
                output : from Text
Parameters    : Data       = one- or two-level data set name
               ,Text       = text of macro references for each row
                             *-Constraint-*: must be enclosed in nrstr:
               ,Text       = %nrstr(%put note: Name:&Name. Sex=&Sex.;)
                             notes: may be any of:
                             * tokens
                             * statements including semicolons
                             * macro calls:
               ,Text       = %nrstr(%MyMacro(Name=&Name.,Sex=&Sex.))
                             recommend use CallMacro for ease of testing
               ,Hex16      = 1 :: default, convert numerics to hex16
                             used to pass real numbers accurately
                                  across step boundaries
               ,Hex16      = 0 :: pass numerics as decimals
               ,Testing    = 0 :: default, no extra messages in log
               ,Testing    = 1 :: for testing, note: auto-reset when
                                  options mprint source2;
               ,Unquote    = 1 :: default, write notes to log
               ,Unquote    = 0 :: do not   write notes to log
                -------------------------------------------------------
Bells,Whistles: writes real time used to log
                note: CALLTEST used real time  0:00:00.016
-----------------------------------------------------------------------
Usage Example:
PROC Freq data   = sashelp.Class;
          tables   Sex
                 / noprint
             out =    Work.Freq_Class_Sex;
run;*necessary;
DATA %calltext(data = Work.Freq_Class_Sex
              ,text = %nrstr(work.Sex_&Sex)
              );*end of data statement;
do until(EndoFile);
   set sashelp.class  end = EndoFile;
   %calltext(data = Work.Freq_Class_Sex
            ,text = %nrstr(if Sex eq "&Sex" then output work.Sex_&Sex;)
            )
   end;
stop;
run;
log:
13         DATA
MPRINT(CALLTEXT):   work.Sex_F
MPRINT(CALLTEXT):   work.Sex_M
18         do until(EndoFile);
19            set sashelp.class
20                end = endoFile;
MPRINT(CALLTEXT):   if Sex eq "F" then output work.Sex_F;
MPRINT(CALLTEXT):   if Sex eq "M" then output work.Sex_M;
25            end;
26         stop;
27         run;
NOTE: There were 19 observations read from the data set SASHELP.CLASS.
NOTE: The data set WORK.Sex_F has  9 observations and 5 variables.
NOTE: The data set WORK.Sex_M has 10 observations and 5 variables.
-----------------------------------------------------------------------
NOTE: aHHa moment provided by Søren Lassen
which resulted in CallText being a derivative work from CallMacr:
http://www.listserv.uga.edu/cgi-bin/wa?A2=ind1203B&L=sas-l&P=R1971
Re: tip: macro implementation of data step link and return
text= %nrstr(Library.GAL_&year._%substr(&m,2)_01(in=Have_%substr(&m,2)))
...
%unquote(&Text)
-----------------------------------------------------------------------
word count: UltraEdit information: <Alt> <Search> <Word Count>
               DateTime: 6/25/2012 7:08:43 AM
                  Words:  695
                  Lines:  160
Characters(no   spaces): 4946
Characters(with spaces): 7194
****** ...................... */
 
%MACRO calltext
         (Data    = sashelp.class
         ,Text    = %nrstr(%put note: Name:&Name. Sex=&Sex.;)
         ,Hex16   = 1 /* convert numerics to hex16? */
         ,Testing = 0
         ,Unquote = 1 /* write notes to log? */
)/ des = 'site: assemble mvar assignment statement(s) then unquote text'
 /**** ** store source /* */
;/* RJF2 3/23/2012 working
****** NOTE: _C_*: avoid name collisions w/data set vars ***/
%local _C_Col _C_Dsid _C_Hex16 _C_Nobs _C_Nvars   _C_Rc
       _C_Row _C_Type _C_Name  _C_Num  _C_Testing _C_Text
       _C_TimeStart _C_TimeEnd;
%let   _C_TimeStart = %sysfunc(datetime(),hex16.);
%let _C_Testing= %eval(   &Testing
                       or(    %sysfunc(getoption(MPRINT))  eq MPRINT
                          and %sysfunc(getoption(SOURCE2)) eq SOURCE2));
%Let _C_Hex16   = &Hex16.;
%Let _C_Text    = &Text.;
%Let _C_Unquote = &Unquote.;
 
%**  description: assertions;
%**  purpose    : if fail then exit;
%if  not(%sysfunc(exist(&Data.))) %then %do;
     %put Err%str()or: &SysMacroname. exiting: not exist(&Data.);
     %return;
     %end;
%let _C_Dsid  = %sysfunc(open (&Data.         ));
%let _C_Nobs  = %sysfunc(attrn(&_C_Dsid.,Nobs ));
%let _C_Nvars = %sysfunc(attrn(&_C_Dsid.,Nvars));
%if  not &_C_Nobs. or not &_C_Nvars. %then %do;
  %put Err%str()or: &SysMacroName. &Data. obs=&_C_Nobs. vars=&_C_Nvars.;
     %goto CloseExit;
     %end;
%else
 %put note: &SysMacroname. reading &Data. obs=&_C_Nobs. vars=&_C_Nvars.;
 
%** description: read data;
%** purpose    : make macro variable assignment(s), submit;
%do _C_Row = 1 %to &_C_Nobs.;
    %*** note:                  fetchobs==read row;
    %let _C_Rc       = %sysfunc(fetchobs(&_C_Dsid.,&_C_Row. ));
    %do _C_Col = 1 %to &_C_Nvars.;
        %let _C_Name = %sysfunc(varname (&_C_Dsid.,&_C_Col. ));
        %let _C_Num  = %sysfunc(varnum  (&_C_Dsid.,&_C_Name.));
        %let _C_Type = %sysfunc(vartype (&_C_Dsid.,&_C_Num. ));
 
        %** assign: for type=C: value, type=N: hex16(value);
        %if   &_C_Type. eq C
           or(&_C_Type. eq N and not &_C_Hex16.) %then
              %let &_C_Name. = %left(%sysfunc(
                         getvar&_C_Type.(&_C_Dsid.,&_C_Num.)));
        %else %let &_C_Name. = %left(%sysfunc(
           putn(%sysfunc(getvar&_C_Type.(&_C_Dsid.,&_C_Num.)),hex16.)));
        %if &_C_Testing. %then %put note: testing &_C_Name.=&&&_C_Name.;
        %end;
 
    %if not &_C_Testing. and &_C_Unquote. %then
        %put note: &SysMacroName returns %cmpres(%unquote(&_C_Text.));
 
    %*** submit: NOTE! no ending semicolon!;
    %unquote(&_C_Text.)
    %end;
%if &_C_Testing. %then %put _local_;
 
%CloseExit: %let _C_Rc = %sysfunc(close(&_C_Dsid.));
%let _C_TimeEnd = %sysfunc(datetime(),hex16.);
%Put note: &SysMacroName used real time %sysfunc
           (putn(&_C_TimeEnd.x-&_C_TimeStart.x,time12.3));
%mend calltext;


Assertions

This function performs the following assertions:

  • exist data?
  • data has rows==Nobs and columns==Nvars

Code and demonstrations have been moved to: Macro_Assertions_for

Examples

Hard-coded Macro Statments

This program provides an illustration of the statements returned by the function which are passed to the SAS parser.

*          initialization for this demo;
6          %Let Sex     = ?;
7          %Let Count   = 0;
8          %Let Percent = 0;
9          %Let Text    = tokens: Sex: &Sex Count: &Count Percent: &Percent;

10         %Let Sex     = F;
11         %Let Count   = 9;
12         %Let Percent = 47;
13         %Put note: 
14         &Text.
15         );
note: tokens: Sex: F Count: 9 Percent: 47

16         %Let Sex     = M;
17         %Let Count   = 10;
18         %Let Percent = 52;
19         %Put note: 
20         &Text.
21         );
note: tokens: Sex: M Count: 10 Percent: 52

Calling an Include

This program calls a parameterized include: Cardinality-Ratio-calculator.

The called program is shown on Cardinality_Ratio#Program:_CrdRatio-demo

 /*    name: <UNC>\SAS-site\macro-tests\
                  calltext-demo-CardRatio-caller.sas
description: test program for calltext
    purpose: demo of list processing routine
author: RJF2 5/12/2012 
*************/    
options mprint source2;*testing==on;
 
*note: parameters for SiteIncl(CrdRatio);
%Let In_Libname = sashelp;
%Let In_Memname = class;
%Let In_Memname = _all_;
 
%Let Libname    =;
%Let Memname    =;
 
%Let Out_Base   = NLevels_all;
%Let Out_Data   = NLevels    ;
%Let Out_Lib    = Work       ;
 
%Let Out_Contents = Contents;*here;
 
PROC Contents data  = &In_Libname..&In_Memname
              out   = &Out_Contents
             (keep  = Libname Memname Memtype Nobs
              where = (Memtype eq 'DATA'  and Nobs))
                      noprint;
 
PROC Sort data = &Out_Contents(drop = Memtype Nobs)
           out = &Out_Contents
                 nodupkey;
           by    Memname;
 
PROC SQL; describe table &Out_Contents;
          quit;
 
PROC Print data = &Out_Contents;
           title3 &Out_Contents;
run;
 
*testing;
%calltext(data = &Out_Contents
         ,text = %nrstr(%put include SiteIncl(CrdRatio);)
         );
 
options nomprint nosource2;*testing==off;
 
%calltext(data = &Out_Contents
         ,text = %nrstr(%include SiteIncl(CrdRatio);)
         );
 
Proc Print data   = &Out_Lib..&Out_Base;
           title3  "Nlevels of &In_Libname..&In_Memname. &Out_Base";
run;

log

NOTE: The data set WORK.CONTENTS has 78 observations and 2 variables.

[... Big Snip ...]

36         %calltext(data = &Out_Contents
37                  ,text = %nrstr(%put include SiteIncl(CrdRatio);)
38                  );
note: CALLTEXT reading Contents obs=78 vars=2
note: testing LIBNAME=SASHELP
note: testing MEMNAME=PRDSAL2
include SiteIncl(CrdRatio)
note: testing LIBNAME=SASHELP
note: testing MEMNAME=PRDSAL3
include SiteIncl(CrdRatio)
note: testing LIBNAME=SASHELP
note: testing MEMNAME=PRDSALE
include SiteIncl(CrdRatio)

[... Big Snip ...]

note: testing LIBNAME=SASHELP
note: testing MEMNAME=ZIPCODE
include SiteIncl(CrdRatio)

[... Big Snip ...]

39         %calltext(data = &Out_Contents
40                  ,text = %nrstr(%include SiteIncl(CrdRatio);)
41                  );
note: CALLTEXT reading Contents obs=76 vars=2
note: CALLTEXT returns %include SiteIncl(CrdRatio);
note: CALLTEXT returns PROC Freq data = SASHELP.ADSMSG nlevels ;

[... Big Snip ...]

note: CALLTEXT used real time  0:00:15.297
7452       Proc Print data   = &Out_Lib..&Out_Base;
7453                  title3  "Nlevels of &In_Libname..&In_Memname. &Out_Base";
7454       run;

NOTE: There were 692 observations read from the data set WORK.NLEVELS_ALL.
NOTE: The PROCEDURE PRINT printed page 78.
NOTE: PROCEDURE PRINT used (Total process time):
      real time           0.01 seconds

[... Big Snip ...]

NOTE: SAS Institute Inc., SAS Campus Drive, Cary, NC USA 27513-2414
NOTE: The SAS System used:
      real time           15.70 seconds

listing

Site Macro Testing
Nlevels of SASHELP._all_ NLevels_all
                                                                           Cardi-
                                                                           nality
Obs  Data_Set         name        T_Len  label                             Ratio       is_a     NLevels   Nobs
[... Big Snip ...]                     
659  SASHELP.ZIPCODE.CITY        c: 35  Name of city/org                 0.45109  foreign key?   18705  41466
660  SASHELP.ZIPCODE.COUNTY      n:  8  FIPS county code.                0.00786  foreign key?     326  41466
661  SASHELP.ZIPCODE.COUNTYNM    c: 25  Name of county/parish.           0.04657  foreign key?    1931  41466
[... Big Snip ...]
666  SASHELP.ZIPCODE.STATE       n:  8  Two-digit number (FIPS code) f   0.00140  foreign key?      58  41466
667  SASHELP.ZIPCODE.STATECODE   c:  2  Two-letter abbrev. for state n   0.00140  foreign key?      58  41466
668  SASHELP.ZIPCODE.STATENAME   c: 25  Full name of state/territory     0.00140  foreign key?      58  41466
669  SASHELP.ZIPCODE.TIMEZONE    c:  9  Time Zone for ZIP Code.          0.00027  foreign key?      11  41466
670  SASHELP.ZIPCODE.X           n:  8  Longitude (degrees) of the cen   0.99756  nmbr: fact?    41365  41466
671  SASHELP.ZIPCODE.Y           n:  8  Latitude (degrees) of the cent   0.99641  nmbr: fact?    41317  41466
672  SASHELP.ZIPCODE.ZIP         n:  8  The 5-digit ZIP Code             1.00000  primary key!?  41466  41466
673  SASHELP.ZIPCODE.ZIP_CLASS   c:  1  ZIP Code Classification:P=PO B   0.00007  foreign key?       3  41466


Splitting a Data Set

Hard-coded

DATA work.Sex_F   (label = "Count: 9 Pcnt:47") 
     work.Sex_M   (label = "Count:10 Pcnt:53")
     ;*end data statement;
do until(EndoFile);
   set sashelp.class
       end = endoFile;
   if      Sex eq "F" then output work.Sex_F;
   else if Sex eq "M" then output work.Sex_M;
   else ;  *** semicolon needed for ending else;
   end;
stop;
run;
 
PROC SQL; describe table work.Sex_F;
          describe table work.Sex_M;
          quit;

Using the CallText function

sashelp.Class.Sex
PROC Freq data   = sashelp.Class;
          tables   Sex
                 / noprint
             out = Work.Freq_Class_Sex;
run;
DATA %calltext(data = Work.Freq_Class_Sex
              ,text = %nrstr
     (work.Sex_&Sex(label="Count:&Count Pcnt:%scan(&Percent.,1,.)"))
              )
     ;*end: data statement;
do until(EndoFile);
   set sashelp.class
       end = endoFile;
   %calltext(data = Work.Freq_Class_Sex
            ,text = 
   (if Sex eq "&Sex" then output work.Sex_&Sex; else)
            )
      ;*semicolon needed for end: else;
   end;
stop;
run;
 
PROC SQL;  %calltext(data = Work.Freq_Class_Sex
                    ,text = (describe table work.Sex_&Sex;)
                    )
           quit;
run;

Log:

8          PROC Freq data   = sashelp.Class;
9                    tables   Sex
10                          / noprint
11                      out = Work.Freq_Class_Sex;
12         run;

NOTE: There were 19 observations read from the data set SASHELP.CLASS.
NOTE: The data set WORK.FREQ_CLASS_SEX has 2 observations and 3 variables.

13         DATA %calltext(data = Work.Freq_Class_Sex
14                       ,text = 
15        (work.Sex_&Sex(label="Count:&Count Pcnt:%scan(&Percent.,1,.)"))
17                       )
note: CALLTEXT reading Work.Freq_Class_Sex obs=2 vars=3
note: CALLTEXT returns work.Sex_F(label="Count:9 Pcnt:47")
note: CALLTEXT returns work.Sex_M(label="Count:10 Pcnt:52")
18              ;*end: data statement;
19         do until(EndoFile);
20            set sashelp.class
21                end = endoFile;
22            %calltext(data = Work.Freq_Class_Sex
23                     ,text = 
24            (if Sex eq "&Sex" then output work.Sex_&Sex; else)
25                     )
note: CALLTEXT reading Work.Freq_Class_Sex obs=2 vars=3
note: CALLTEXT returns if Sex eq "F" then output work.Sex_F; else
note: CALLTEXT returns if Sex eq "M" then output work.Sex_M; else
26               ;*semicolon needed for end: else;
27            end;
28         stop;
29         run;

NOTE: There were 19 observations read from the data set SASHELP.CLASS.
NOTE: The data set WORK.SEX_F has  9 observations and 5 variables.
NOTE: The data set WORK.SEX_M has 10 observations and 5 variables.

31         PROC SQL;
31       !            %calltext(data = Work.Freq_Class_Sex
32                             ,text = (describe table work.Sex_&Sex;)
33                             )
note: CALLTEXT reading Work.Freq_Class_Sex obs=2 vars=3
note: CALLTEXT returns describe table work.Sex_F;
NOTE: SQL table WORK.SEX_F was created like:

create table WORK.SEX_F( label='Count:9 Pcnt:47' bufsize=4096 )
  (
   Name char(8),
   Sex char(1),
   Age num,
   Height num,
   Weight num
  );

note: CALLTEXT returns describe table work.Sex_M;
NOTE: SQL table WORK.SEX_M was created like:

create table WORK.SEX_M( label='Count:10 Pcnt:52' bufsize=4096 )
  (
   Name char(8),
   Sex char(1),
   Age num,
   Height num,
   Weight num
  );
34                    quit;


sashelp.Zipcode.Zip3

USPS has a central processing facility for a zipcode whose code is ???00.

Task: provide a data set with the all the zipcodes of the central processing facility.

*name       : \SAS-site\macros-tests\calltext-demo-sashelp-class-sex.sas
*description: split a data set based on values of class variable
*purpose    : demo and test suite for CallText;
 
*options mprint;*testing macro;
*options mprint source2;*testing function notes;
*options obs = 33;
 
%Let In_Lib   = sashelp;
%Let In_Data  = ZipCode;
 
%Let Out_Data  = work.ZipCode3;
%Let Out_List = Work.List_State_Zip3;
 
Proc SQL; describe table &In_Lib..&In_Data.;
          quit;
 
DATA Work.&In_Data;*(drop = Zip prev_Zip3);
attrib Zip3 length = $3;
do until(EndoFile);
   set &In_Lib..&In_Data.
       end = EndoFile;
   Zip3 = put(Zip,z5.);
   output;
   end;
stop;
run;
 
Proc SQL; describe table &SysLast.;
          quit;
 
PROC Freq data   = &SysLast.(keep = StateCode Zip3);
          tables   StateCode* Zip3
                 / list missing noprint
            out = &Out_List.;
 
*note: optimize for data subsetting if;
PROC SORT data = &SysLast.
           out = &SysLast.;
           by    descending Count;            
run;
DATA %calltext(data = &Out_List
              ,text = %nrstr
              (work.&StateCode._&Zip3.
              (label="Count:&Count. 
                      Percent:%scan(&Percent.,1,.).%substr
              (%scan(&Percent.,2,.),1,3)"))
              ,hex16=0
              )
     ;*end: data statement;
attrib Zip3 length = $3;
do until(EndoFile);
   set Work.&In_Data.
       end = endoFile;
   *Zip3 = put(Zip,z5.);
   %calltext(data = &Out_List
            ,text = %nrstr
      (if StateCode eq "&StateCode" and Zip3 eq "&Zip3." then
          output work.&StateCode._&Zip3.; else)
            )
      ;*semicolon needed for end: else;
   end;
stop;
run;
 
/**********************************************************************
PROC SQL;  %calltext(data = &Out_List
                    ,text = %nrstr
                    (describe table work.&StateCode._&Zip3.;)
                    )
           quit;
/**********************************************************************/
 
PROC SORT data = &Out_List.
           out = &Out_List.;
           by    StateCode Zip3;            
run;
%calltext(data = &Out_List
         ,text = %nrstr
         (Proc Print data = work.&StateCode._&Zip3.(obs=3);
          title3 "State: &StateCode. Zip3: &Zip3.";
          title4 "Count: &Count.";
          title5 "Percent: &Percent.";run;
         )
         ,hex16=0
         )
run;

Log:

[... Big Snip ...]
NOTE: There were 41466 observations read from the data set WORK.ZIPCODE.
[... Big Snip ...]
NOTE: The data set WORK.LIST_STATE_ZIP3 has 922 observations and 4 variables.
[... Big Snip ...]
42         DATA %calltext(data = &Out_List
43                       ,text = %nrstr
44                       (work.&StateCode._&Zip3.
45                       (label="Count:&Count.
46                               Percent:%scan(&Percent.,1,.).%substr
47                       (%scan(&Percent.,2,.),1,2)"))
48                       ,hex16=0
49                       )
note: CALLTEXT reading Work.List_State_Zip3 obs=922 vars=4
note: CALLTEXT returns work.TX_770 (label="Count:99 Percent:0.23")
note: CALLTEXT returns work.MN_553 (label="Count:97 Percent:0.23")
note: CALLTEXT returns work.CA_900 (label="Count:95 Percent:0.22")

[... Big Snip ...]

note: CALLTEXT returns work.VA_205 (label="Count:1 Percent:0.00")
note: CALLTEXT returns work.WY_821 (label="Count:1 Percent:0.00")
note: CALLTEXT returns work.WY_834 (label="Count:1 Percent:0.00")
note: CALLTEXT used real time  0:00:07.672
50              ;*end: data statement;
51         attrib Zip3 length = $3;
52         do until(EndoFile);
53            set Work.&In_Data.
54                end = endoFile;
55            *Zip3 = put(Zip,z5.);
56            %calltext(data = &Out_List
57                     ,text = %nrstr
58               (if StateCode eq "&StateCode" and Zip3 eq "&Zip3." then
59                   output work.&StateCode._&Zip3.; else)
60                     )
note: CALLTEXT reading Work.List_State_Zip3 obs=922 vars=4
note: CALLTEXT returns if StateCode eq "TX" and Zip3 eq "770" then output work.TX_770; else
note: CALLTEXT returns if StateCode eq "MN" and Zip3 eq "553" then output work.MN_553; else
note: CALLTEXT returns if StateCode eq "CA" and Zip3 eq "900" then output work.CA_900; else

[... Big Snip ...]

note: CALLTEXT returns if StateCode eq "VA" and Zip3 eq "205" then output work.VA_205; else
note: CALLTEXT returns if StateCode eq "WY" and Zip3 eq "821" then output work.WY_821; else
note: CALLTEXT returns if StateCode eq "WY" and Zip3 eq "834" then output work.WY_834; else
note: CALLTEXT used real time  0:00:05.046
61               ;*semicolon needed for end: else;
62            end;
63         stop;
64         run;

NOTE: There were 41466 observations read from the data set WORK.ZIPCODE.
NOTE: The data set WORK.TX_770 has 99 observations and 20 variables.
NOTE: The data set WORK.MN_553 has 97 observations and 20 variables.
NOTE: The data set WORK.CA_900 has 95 observations and 20 variables.

[... Big Snip ...]

NOTE: The data set WORK.VA_205 has 1 observations and 20 variables.
NOTE: The data set WORK.WY_821 has 1 observations and 20 variables.
NOTE: The data set WORK.WY_834 has 1 observations and 20 variables.
NOTE: DATA statement used (Total process time):
      real time           39.40 seconds

[... Big Snip ...]

note: CALLTEXT reading Work.List_State_Zip3 obs=922 vars=4
note: CALLTEXT returns Proc Print data = work.AK_995(obs=3); 
title3 "State: AK Zip3: 995"; 
title4 "Count: 69"; 
title5 "Percent: 0.16640138908985";
run;
NOTE: There were 3 observations read from the data set WORK.AK_995.

[... Big Snip ...]

note: CALLTEXT returns Proc Print data = work.WY_834(obs=3); 
title3 "State: WY Zip3: 834"; title4 "Count: 1"; title5 "Percent: run;
NOTE: There were 1 observations read from the data set WORK.WY_834.

NOTE: The PROCEDURE PRINT printed page 922.
NOTE: PROCEDURE PRINT used (Total process time):
      real time           0.01 seconds

[... Big Snip ...]

note: CALLTEXT used real time  0:00:43.609
87         
88         
89         run;

NOTE: SAS Institute Inc., SAS Campus Drive, Cary, NC USA 27513-2414
NOTE: The SAS System used:
      real time           1:29.34

Data Review using formats

predecessor: Macro_Invalid_for_Data_Review

 /*    name: ...\SAS-site\sas-macro-tests
              calltext-data-review-demo-sashelp-class.sas;
description: data review with user-defined formats to identify outliers
purpose    : test suite for CallText
RJF2 4/11/2012 7:58:09 AM
RJF  1/13/2013 3:24:54 PM for sas.wiki.CallText
****/
 
*options mprint;* source2;*testing;
*options mprint source2;*testing;
 
**** used in proc format and macro DataRevu;
%Let Fmt_Invalid = invalid;
 
*description: make user-defined formats with other=;
PROC Format library = work
            cntlout = Work.Format_Values_Other
            (where = (HLO = "O"));
            title3 fmtlib;
            value $Gender
                  'F' = 'female'
                  'M' = 'male'
                other = "&Fmt_Invalid.";
            value Height
                51.3 <-< 72 = 'expected'
                other = "&Fmt_Invalid.";
            value Weight
                50.5 <-< 150 = 'expected'
                other = "&Fmt_Invalid.";
run;
 
*description: make a value for formats with other;
*purpose    : use with CallText;
DATA Work.CntlIn;
     retain FmtName '$_HaveOther'
            HLO    ' '
            Label  '1' %*one==true;
            Type   'C';
do until(EndoFile);
   set Work.Format_Values_Other
      (keep =    FmtName Type
       rename = (FmtName = Start
                 Type    = TypeOld))
       end = EndoFile;
   if TypeOld = 'C' then Start = catt('$',Start);
   output;
   end;
HLO   = "O";*Oh==Other;
Label = '0';*zero==false;
output;
stop;
 
PROC Print data = &SysLast.;
           title3 &SysLast.;
 
PROC Format library = Work
            cntlin  = Work.CntlIn
            ;*fmtlib;
 
run;
 
* description: add formats and invalid Gender;
DATA Work.Class;
     if 0 then set sashelp.class;
     attrib Sex    format = $Gender. label = 'gender'
            Height format = Height.
            Weight format = Weight.;
do until(EndoFile);
   set sashelp.class end = EndoFile;
   output;
   end;
****   add the invalid row;
Name = 'Chris';
Sex  = 'I';
output;
stop;
run;
 
*description: save Contents with Name and Format;
PROC Contents data = Work.Class
                     noprint
              out  = Work.Contents
             (keep = NAME    %*char(32) label='Variable Name',  ;
                     LABEL   %*char(256) label='Variable Label',;
                     FORMAT  %*char(32) label='Variable Format',;
             where = (        Format ne ' '
                      and put(Format,$_HaveOther.)
             )
             );*note keep list must match macro DataRevu parm list;
 
PROC SQL; describe table Work.Class;
          describe table Work.Contents;
          quit;
 
PROC Print data = Work.Contents;
           title3 Work.Contents;
 
DATA Work.Data_For_Review;
do until(EndoFile);
   set Work.Class end = EndoFile;
   %calltext(Data = Work.Contents
            ,text = %nrstr
   (if put(&Name.,&Format..) eq "&Fmt_Invalid." then output;else)
            );
   *note: semicolon after close paren terminates else statement;
   end;
stop;
 
Proc Print data = &SysLast.;
           title3 &SysLast.;
           format _all_;
run;

output

WORK.CNTLIN
                                                        Type
Obs      FmtName      HLO    Label    Type     Start     Old

 1     $_HaveOther             1       C      HEIGHT      N  
 2     $_HaveOther             1       C      WEIGHT      N  
 3     $_HaveOther             1       C      $GENDER     C  
 4     $_HaveOther     O       0       C      $GENDER     C  

 
Work.Contents
Obs    NAME      LABEL     FORMAT

 1     Height              HEIGHT 
 2     Sex       gender    $GENDER
 3     Weight              WEIGHT 
 
 
WORK.DATA_FOR_REVIEW
Obs     Name     Sex    Age    Height    Weight
---    ------    ---    ---    ------    ------ 
 1     Joyce      F      11     51.3       50.5
 2     Philip     M      16     72.0      150.0
 3     Chris      I      15     66.5      112.0

References

--Ronald_J._Fehd macro.maven == the radical programmer 07:14, 24 April 2012 (EDT)