As the first step in the decommissioning of sasCommunity.org the site has been converted to read-only mode.


Here are some tips for How to share your SAS knowledge with your professional network.


Difference between revisions of "Macro CallText"

From sasCommunity
Jump to: navigation, search
m (added Category: Design Elements for Macros)
(2016-10-10 replaced macro calltext after presenting paper)
Line 13: Line 13:
 
*purpose    : test suite for calltext;
 
*purpose    : test suite for calltext;
  
%Let Sex = ?;
+
%let sex = ?;
%Let Count = 0;
+
%let count = 0;
%Let Percent = 0;
+
%let percent = 0;
%Let Text = %nrstr(tokens: Sex: &Sex Count: &Count Percent: &Percent);
+
%let text = %nrstr(tokens: sex: &sex count: &count percent: &percent);
%Let Sex = F;
+
%let sex = f;
%Let Count = 9;
+
%let count = 9;
%Let Percent = 47;
+
%let percent = 47;
%Put note: %unquote(
+
%put note: %unquote(&text);
&Text.
+
%let sex = m;
);
+
%let count = 10;
%Let Sex = M;
+
%let percent = 52;
%Let Count = 10;
+
%put note: %unquote(&text);
%Let Percent = 52;
+
%put;
%Put note: %unquote(
+
&Text.
+
);
+
%Put;
+
 
</source>
 
</source>
  
Line 36: Line 32:
  
 
<pre>
 
<pre>
note: tokens: Sex: F Count: 9 Percent: 47
+
note: tokens: sex: f count: 9 percent: 47
15        %Let Sex = M;
+
15        %let sex = m;
16        %Let Count = 10;
+
16        %let count = 10;
17        %Let Percent = 52;
+
17        %let percent = 52;
18        %Put note: %unquote(
+
18        %put note: %unquote(&text);
19        &Text.
+
note: tokens: sex: m count: 10 percent: 52
20        );
+
note: tokens: Sex: M Count: 10 Percent: 52
+
 
</pre>
 
</pre>
  
 
=== CallText ===
 
=== CallText ===
 +
 +
note: published in
 +
[http://www.mwsug.org/proceedings/2016/TT/MWSUG-2016-TT06.pdf MWSUG-2016, Tools of the Trade, paper TT06]
  
 
<source lang="sas">
 
<source lang="sas">
  /*       Name: calltext.sas
+
  /* name: <UNC>\SAS-site\macros\calltext.sas
/*  location: <UNC>\SAS-site\macros
+
  author: Ronald J. Fehd 2012
        Author: Ronald J. Fehd 2012
+
          ----------------------------------------------------
                -------------------------------------------------------
+
Summary : description  : call text with specified
Summary       : description  : call text with specified
+
                        values in data set as parameters
                              values in data set as parameters
+
          purpose      : provide generic method to call text
                purpose      : provide generic method to call text
+
                        using list==control data set of parms
                              using list==control data set of parms
+
          ----------------------------------------------------
                -------------------------------------------------------
+
Contexts: program group: list processing token generator
Contexts     : program group: list processing token generator
+
          program  type: function
                program  type: function
+
          SAS      type: macro assignment statement generator
                SAS      type: macro assignment statement generator
+
          uses routines: n/a
                uses routines: n/a
+
          ----------------------------------------------------
                -------------------------------------------------------
+
Specifications: input  : required: data, text
Specifications: input  : required: Data, Text
+
                         optional: delimiter, hex16
                         optional: Hex16
+
                 process: assemble macro variable assignment(s)
                 process: assemble macro variable assignment(s), call
+
                        call
                 output : from Text
+
                 output : from text
Parameters   : Data      = one- or two-level data set name
+
Parameters: data    = one- or two-level data set name
              ,Text      = text of macro references for each row
+
          ,text    = text of macro references for each row
                            *-Constraint-*: must be enclosed in nrstr:
+
      *-constraint-*: must be enclosed in nrstr:
              ,Text      = %nrstr(%put note: Name:&Name. Sex=&Sex.;)
+
          ,text    = %nrstr(%put note: name:&name sex=&sex;)
                            notes: may be any of:
+
                      notes: may be any of:
                            * tokens
+
                      * tokens
                            * statements including semicolons
+
                      * statements including semicolons
                            * macro calls:
+
                      * macro calls:
              ,Text      = %nrstr(%MyMacro(Name=&Name.,Sex=&Sex.))
+
          ,text    = %nrstr(%mymacro(name=&name,sex=&sex))
                            recommend use CallMacro for ease of testing
+
          ,hex16  = 1 :: default, convert numeric to hex16
              ,Hex16      = 1 :: default, convert numerics to hex16
+
                      used to pass real numbers accurately
                            used to pass real numbers accurately
+
                          across step boundaries
                                  across step boundaries
+
          ,hex16  = 0 :: pass numerics as decimals
              ,Hex16      = 0 :: pass numerics as decimals
+
          ,testing = 0 :: default, no extra messages in log
              ,Testing    = 0 :: default, no extra messages in log
+
          ,testing = 1 :: note: auto-reset when
              ,Testing    = 1 :: for testing, note: auto-reset when
+
                          options mprint source2;
                                  options mprint source2;
+
          ,unquote = 1 :: default, write notes to log
              ,Unquote    = 1 :: default, write notes to log
+
          ,unquote = 0 :: do not  write notes to log
              ,Unquote    = 0 :: do not  write notes to log
+
            --------------------------------------------------
                -------------------------------------------------------
+
bells, whistles: writes real time used to log
Bells,Whistles: writes real time used to log
+
                note: CALLTEXT used real time  0:00:00.016
                note: CALLTEST used real time  0:00:00.016
+
-----------------------------------------------------------
-----------------------------------------------------------------------
+
usage example:
Usage Example:
+
PROC freq data  = sashelp.class;
PROC Freq data  = sashelp.Class;
+
           tables  sex / noprint
           tables  Sex
+
             out = list_values;
                / noprint
+
             out =   Work.Freq_Class_Sex;
+
 
run;*necessary;
 
run;*necessary;
DATA %calltext(data = Work.Freq_Class_Sex
+
DATA %calltext(data = list_values
               ,text = %nrstr(work.Sex_&Sex)
+
               ,text = %nrstr(work.sex_&sex)
 
               );*end of data statement;
 
               );*end of data statement;
do until(EndoFile);
+
do until(endofile);
   set sashelp.class  end = EndoFile;
+
   set sashelp.class  end = endofile;
   %calltext(data = Work.Freq_Class_Sex
+
   %calltext(data     = list_values
             ,text = %nrstr(if Sex eq "&Sex" then output work.Sex_&Sex;)
+
            ,delimiter = %nrstr(else)
 +
             ,text
 +
  =%nrstr(if sex eq "&sex" then output work.sex_&sex;)
 
             )
 
             )
 
   end;
 
   end;
 
stop;
 
stop;
 
run;
 
run;
log:
+
log: ---------------------------------------------------
13         DATA
+
13     DATA
MPRINT(CALLTEXT):  work.Sex_F
+
MPRINT(CALLTEXT):  work.sex_F
MPRINT(CALLTEXT):  work.Sex_M
+
MPRINT(CALLTEXT):  work.sex_M
18         do until(EndoFile);
+
18     do until(EndoFile);
19           set sashelp.class
+
19       set sashelp.class end = endoFile;
20                end = endoFile;
+
MPRINT(CALLTEXT): if Sex eq "F" then output work.sex_F;
MPRINT(CALLTEXT):   if Sex eq "F" then output work.Sex_F;
+
MPRINT(CALLTEXT): else
MPRINT(CALLTEXT):   if Sex eq "M" then output work.Sex_M;
+
MPRINT(CALLTEXT): if Sex eq "M" then output work.sex_M;
25           end;
+
25       end;
26         stop;
+
26     stop;
27         run;
+
27     run;
NOTE: There were 19 observations read from the data set SASHELP.CLASS.
+
NOTE: There were 19 obs read from data set SASHELP.CLASS
NOTE: The data set WORK.Sex_F has  9 observations and 5 variables.
+
NOTE: The data set WORK.sex_F has  9 obs and 5 variables
NOTE: The data set WORK.Sex_M has 10 observations and 5 variables.
+
NOTE: The data set WORK.sex_M has 10 obs and 5 variables
-----------------------------------------------------------------------
+
--------------------------------------------------------
NOTE: aHHa moment provided by Søren Lassen
+
DateTime: 2016-09-21 7:14:10 AM
which resulted in CallText being a derivative work from CallMacr:
+
word count:       words696
http://www.listserv.uga.edu/cgi-bin/wa?A2=ind1203B&L=sas-l&P=R1971
+
                   lines159
Re: tip: macro implementation of data step link and return
+
characters(no  spaces): 4610
text= %nrstr(Library.GAL_&year._%substr(&m,2)_01(in=Have_%substr(&m,2)))
+
characters(with spaces): 6643
...
+
%unquote(&Text)
+
-----------------------------------------------------------------------
+
word count: UltraEdit information: <Alt> <Search> <Word Count>
+
              DateTime: 6/25/2012 7:08:43 AM
+
                  Words695
+
                   Lines160
+
Characters(no  spaces): 4946
+
Characters(with spaces): 7194
+
 
****** ...................... */
 
****** ...................... */
 
 
%MACRO calltext
 
%MACRO calltext
        (Data    = sashelp.class
+
        (data    = sashelp.class
        ,Text    = %nrstr(%put note: Name:&Name. Sex=&Sex.;)
+
        ,text    = %nrstr(%put note: name:&name sex=&sex;)
        ,Hex16   = 1 /* convert numerics to hex16? */
+
        ,delimiter= /* %nrstr(else) */
        ,Testing = 0
+
        ,global   = 0 /* make mvars global? */
        ,Unquote = 1 /* write notes to log? */
+
        ,hex16    = 1 /* convert numerics to hex16? */
)/ des = 'site: assemble mvar assignment statement(s) then unquote text'
+
        ,testing  = 0
  /**** ** store source /* */
+
        ,unquote  = 1 /* write notes to log? */
;/* RJF2 3/23/2012 working
+
)/ des =
****** NOTE: _C_*: avoid name collisions w/data set vars ***/
+
'site: assemble mvar assignment statement(s), unquote text'
%local _C_Col _C_Dsid _C_Hex16 _C_Nobs _C_Nvars  _C_Rc
+
  /** * store source /* */
       _C_Row _C_Type _C_Name _C_Num _C_Testing _C_Text
+
;/**** NOTE: _*: avoid name collisions w/data set vars ***/
       _C_TimeStart _C_TimeEnd;
+
%local _delimiter _global _hex16 _text _testing _unquote
%let   _C_TimeStart = %sysfunc(datetime(),hex16.);
+
       _dsid _rc _obs _n_obs    _var _n_vars
%let _C_Testing= %eval(  &Testing
+
       _name _num _type          _time_start _time_end;
                      or(    %sysfunc(getoption(MPRINT))  eq MPRINT
+
%let _testing = %eval(not(0 eq &testing)
                          and %sysfunc(getoption(SOURCE2)) eq SOURCE2));
+
        or(    %sysfunc(getoption(mprint))  eq MPRINT
%Let _C_Hex16  = &Hex16.;
+
          and %sysfunc(getoption(source2)) eq SOURCE2));
%Let _C_Text   = &Text.;
+
%let _time_start= %sysfunc(datetime(),hex16);
%Let _C_Unquote = &Unquote.;
+
%let _delimiter = &delimiter;
 +
%let _global   = %eval(not(0 eq &global));
 +
%let _hex16    = %eval(not(0 eq &hex16));
 +
%let _text      = &text;
 +
%let _unquote  = %eval(not(0 eq &unquote));
  
 
%**  description: assertions;
 
%**  description: assertions;
 
%**  purpose    : if fail then exit;
 
%**  purpose    : if fail then exit;
%if  not(%sysfunc(exist(&Data.))) %then %do;
+
%if  not(%sysfunc(exist(&data))) %then %do;
     %put Err%str()or: &SysMacroname. exiting: not exist(&Data.);
+
     %put Err%str()or &sysmacroname: not exist(&data);
 
     %return;
 
     %return;
 
     %end;
 
     %end;
%let _C_Dsid  = %sysfunc(open (&Data.        ));
+
%let _dsid  = %sysfunc(open (&data      ));
%let _C_Nobs = %sysfunc(attrn(&_C_Dsid.,Nobs ));
+
%let _n_obs = %sysfunc(attrn(&_dsid,nobs ));
%let _C_Nvars = %sysfunc(attrn(&_C_Dsid.,Nvars));
+
%let _n_vars = %sysfunc(attrn(&_dsid,nvars));
%if  not &_C_Nobs. or not &_C_Nvars. %then %do;
+
%put info: &sysmacroname &=data &=_n_obs &=_n_vars;
  %put Err%str()or: &SysMacroName. &Data. obs=&_C_Nobs. vars=&_C_Nvars.;
+
%if  not &_n_obs or not &_n_vars %then %do;
     %goto CloseExit;
+
    %put Err%str()or &sysmacroname exit: not(nobs and vars);
 +
     %goto close_exit;
 
     %end;
 
     %end;
%else
 
%put note: &SysMacroname. reading &Data. obs=&_C_Nobs. vars=&_C_Nvars.;
 
  
 
%** description: read data;
 
%** description: read data;
 
%** purpose    : make macro variable assignment(s), submit;
 
%** purpose    : make macro variable assignment(s), submit;
%do _C_Row = 1 %to &_C_Nobs.;
+
%do _obs = 1 %to &_n_obs;%*** fetchobs==read row;
    %*** note:                  fetchobs==read row;
+
     %let _rc       = %sysfunc(fetchobs(&_dsid,&_obs ));
     %let _C_Rc       = %sysfunc(fetchobs(&_C_Dsid.,&_C_Row. ));
+
     %do _var = 1 %to &_n_vars;
     %do _C_Col = 1 %to &_C_Nvars.;
+
         %let _name = %sysfunc(varname (&_dsid,&_var ));
         %let _C_Name = %sysfunc(varname (&_C_Dsid.,&_C_Col. ));
+
         %let _num = %sysfunc(varnum  (&_dsid,&_name));
         %let _C_Num = %sysfunc(varnum  (&_C_Dsid.,&_C_Name.));
+
         %let _type = %sysfunc(vartype (&_dsid,&_num ));
         %let _C_Type = %sysfunc(vartype (&_C_Dsid.,&_C_Num. ));
+
        %if &_global %then %global &_name;
 
+
        %else              %local  &_name;
 
         %** assign: for type=C: value, type=N: hex16(value);
 
         %** assign: for type=C: value, type=N: hex16(value);
         %if  &_C_Type. eq C
+
         %if  &_type eq C
           or(&_C_Type. eq N and not &_C_Hex16.) %then
+
           or(&_type eq N and not &_hex16) %then
               %let &_C_Name. = %left(%sysfunc(
+
               %let &_name = %left(%sysfunc(
                        getvar&_C_Type.(&_C_Dsid.,&_C_Num.)));
+
                      getvar&_type(&_dsid,&_num)));
         %else %let &_C_Name. = %left(%sysfunc(
+
         %else %let &_name = %left(%sysfunc(putn(
          putn(%sysfunc(getvar&_C_Type.(&_C_Dsid.,&_C_Num.)),hex16.)));
+
              %sysfunc(getvar&_type(&_dsid,&_num)),hex16)));
         %if &_C_Testing. %then %put note: testing &_C_Name.=&&&_C_Name.;
+
         %if &_testing or &_global %then
 +
            %put echo: &_name=&&&_name;
 
         %end;
 
         %end;
  
     %if not &_C_Testing. and &_C_Unquote. %then
+
     %if not &_testing and &_unquote %then
         %put note: &SysMacroName returns %cmpres(%unquote(&_C_Text.));
+
         %put &sysmacroname output: %cmpres(%unquote(&_text));
 +
    %*** submit: note! no ending semicolon!;
 +
    %unquote(&_text)
  
     %*** submit: NOTE! no ending semicolon!;
+
     %if %length(&_delimiter) and &_obs lt &_n_obs %then %do;
    %unquote(&_C_Text.)
+
        %if not &_testing and &_unquote %then
 +
            %put &sysmacroname output: %unquote(&_delimiter);
 +
        %unquote(&_delimiter)
 +
        %end;
 
     %end;
 
     %end;
%if &_C_Testing. %then %put _local_;
+
%if &_testing %then %put _local_;
  
%CloseExit: %let _C_Rc = %sysfunc(close(&_C_Dsid.));
+
%close_exit: %let _rc      = %sysfunc(close(&_dsid));
%let _C_TimeEnd = %sysfunc(datetime(),hex16.);
+
            %let _time_end = %sysfunc(datetime(),hex16);
%Put note: &SysMacroName used real time %sysfunc
+
%put info: &sysmacroname used real time %sysfunc
           (putn(&_C_TimeEnd.x-&_C_TimeStart.x,time12.3));
+
           (putn(&_time_end.x-&_time_start.x,time12.3));
 
%mend calltext;
 
%mend calltext;
 
</source>
 
</source>
 
 
  
 
== Assertions ==
 
== Assertions ==
Line 238: Line 232:
 
11        %Let Count  = 9;
 
11        %Let Count  = 9;
 
12        %Let Percent = 47;
 
12        %Let Percent = 47;
13        %Put note:  
+
13        %Put note:
 
14        &Text.
 
14        &Text.
 
15        );
 
15        );
Line 246: Line 240:
 
17        %Let Count  = 10;
 
17        %Let Count  = 10;
 
18        %Let Percent = 52;
 
18        %Let Percent = 52;
19        %Put note:  
+
19        %Put note:
 
20        &Text.
 
20        &Text.
 
21        );
 
21        );
Line 263: Line 257:
 
description: test program for calltext
 
description: test program for calltext
 
     purpose: demo of list processing routine
 
     purpose: demo of list processing routine
author: RJF2 5/12/2012  
+
author: RJF2 5/12/2012
*************/  
+
*************/
 
options mprint source2;*testing==on;
 
options mprint source2;*testing==on;
  
Line 378: Line 372:
 
                                                                           nality
 
                                                                           nality
 
Obs  Data_Set        name        T_Len  label                            Ratio      is_a    NLevels  Nobs
 
Obs  Data_Set        name        T_Len  label                            Ratio      is_a    NLevels  Nobs
[... Big Snip ...]                    
+
[... Big Snip ...]
 
659  SASHELP.ZIPCODE.CITY        c: 35  Name of city/org                0.45109  foreign key?  18705  41466
 
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
 
660  SASHELP.ZIPCODE.COUNTY      n:  8  FIPS county code.                0.00786  foreign key?    326  41466
Line 399: Line 393:
  
 
<source lang="sas">
 
<source lang="sas">
DATA work.Sex_F  (label = "Count: 9 Pcnt:47")  
+
DATA work.Sex_F  (label = "Count: 9 Pcnt:47")
 
     work.Sex_M  (label = "Count:10 Pcnt:53")
 
     work.Sex_M  (label = "Count:10 Pcnt:53")
 
     ;*end data statement;
 
     ;*end data statement;
Line 415: Line 409:
 
           describe table work.Sex_M;
 
           describe table work.Sex_M;
 
           quit;
 
           quit;
</source>  
+
</source>
  
 
==== Using the CallText function ====
 
==== Using the CallText function ====
Line 436: Line 430:
 
       end = endoFile;
 
       end = endoFile;
 
   %calltext(data = Work.Freq_Class_Sex
 
   %calltext(data = Work.Freq_Class_Sex
             ,text =  
+
             ,text =
 
   (if Sex eq "&Sex" then output work.Sex_&Sex; else)
 
   (if Sex eq "&Sex" then output work.Sex_&Sex; else)
 
             )
 
             )
Line 449: Line 443:
 
           quit;
 
           quit;
 
run;
 
run;
</source>  
+
</source>
  
 
Log:
 
Log:
Line 464: Line 458:
  
 
13        DATA %calltext(data = Work.Freq_Class_Sex
 
13        DATA %calltext(data = Work.Freq_Class_Sex
14                      ,text =  
+
14                      ,text =
 
15        (work.Sex_&Sex(label="Count:&Count Pcnt:%scan(&Percent.,1,.)"))
 
15        (work.Sex_&Sex(label="Count:&Count Pcnt:%scan(&Percent.,1,.)"))
 
17                      )
 
17                      )
Line 475: Line 469:
 
21                end = endoFile;
 
21                end = endoFile;
 
22            %calltext(data = Work.Freq_Class_Sex
 
22            %calltext(data = Work.Freq_Class_Sex
23                    ,text =  
+
23                    ,text =
 
24            (if Sex eq "&Sex" then output work.Sex_&Sex; else)
 
24            (if Sex eq "&Sex" then output work.Sex_&Sex; else)
 
25                    )
 
25                    )
Line 564: Line 558:
 
                 / list missing noprint
 
                 / list missing noprint
 
             out = &Out_List.;
 
             out = &Out_List.;
           
+
 
 
*note: optimize for data subsetting if;
 
*note: optimize for data subsetting if;
 
PROC SORT data = &SysLast.
 
PROC SORT data = &SysLast.
 
           out = &SysLast.;
 
           out = &SysLast.;
           by    descending Count;          
+
           by    descending Count;
 
run;
 
run;
 
DATA %calltext(data = &Out_List
 
DATA %calltext(data = &Out_List
 
               ,text = %nrstr
 
               ,text = %nrstr
 
               (work.&StateCode._&Zip3.
 
               (work.&StateCode._&Zip3.
               (label="Count:&Count.  
+
               (label="Count:&Count.
 
                       Percent:%scan(&Percent.,1,.).%substr
 
                       Percent:%scan(&Percent.,1,.).%substr
 
               (%scan(&Percent.,2,.),1,3)"))
 
               (%scan(&Percent.,2,.),1,3)"))
Line 601: Line 595:
 
           quit;
 
           quit;
 
/**********************************************************************/
 
/**********************************************************************/
         
+
 
 
PROC SORT data = &Out_List.
 
PROC SORT data = &Out_List.
 
           out = &Out_List.;
 
           out = &Out_List.;
           by    StateCode Zip3;          
+
           by    StateCode Zip3;
 
run;
 
run;
 
%calltext(data = &Out_List
 
%calltext(data = &Out_List
Line 688: Line 682:
  
 
note: CALLTEXT reading Work.List_State_Zip3 obs=922 vars=4
 
note: CALLTEXT reading Work.List_State_Zip3 obs=922 vars=4
note: CALLTEXT returns Proc Print data = work.AK_995(obs=3);  
+
note: CALLTEXT returns Proc Print data = work.AK_995(obs=3);
title3 "State: AK Zip3: 995";  
+
title3 "State: AK Zip3: 995";
title4 "Count: 69";  
+
title4 "Count: 69";
 
title5 "Percent: 0.16640138908985";
 
title5 "Percent: 0.16640138908985";
 
run;
 
run;
Line 697: Line 691:
 
[... Big Snip ...]
 
[... Big Snip ...]
  
note: CALLTEXT returns Proc Print data = work.WY_834(obs=3);  
+
note: CALLTEXT returns Proc Print data = work.WY_834(obs=3);
 
title3 "State: WY Zip3: 834"; title4 "Count: 1"; title5 "Percent: run;
 
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: There were 1 observations read from the data set WORK.WY_834.
Line 708: Line 702:
  
 
note: CALLTEXT used real time  0:00:43.609
 
note: CALLTEXT used real time  0:00:43.609
87        
+
87
88        
+
88
 
89        run;
 
89        run;
  
Line 843: Line 837:
 
Obs      FmtName      HLO    Label    Type    Start    Old
 
Obs      FmtName      HLO    Label    Type    Start    Old
  
  1    $_HaveOther            1      C      HEIGHT      N
+
  1    $_HaveOther            1      C      HEIGHT      N
  2    $_HaveOther            1      C      WEIGHT      N
+
  2    $_HaveOther            1      C      WEIGHT      N
  3    $_HaveOther            1      C      $GENDER    C
+
  3    $_HaveOther            1      C      $GENDER    C
  4    $_HaveOther    O      0      C      $GENDER    C
+
  4    $_HaveOther    O      0      C      $GENDER    C
 +
 
  
 
 
Work.Contents
 
Work.Contents
 
Obs    NAME      LABEL    FORMAT
 
Obs    NAME      LABEL    FORMAT
  
  1    Height              HEIGHT  
+
  1    Height              HEIGHT
 
  2    Sex      gender    $GENDER
 
  2    Sex      gender    $GENDER
  3    Weight              WEIGHT  
+
  3    Weight              WEIGHT
+
 
+
 
 
WORK.DATA_FOR_REVIEW
 
WORK.DATA_FOR_REVIEW
 
Obs    Name    Sex    Age    Height    Weight
 
Obs    Name    Sex    Age    Height    Weight
---    ------    ---    ---    ------    ------  
+
---    ------    ---    ---    ------    ------
 
  1    Joyce      F      11    51.3      50.5
 
  1    Joyce      F      11    51.3      50.5
 
  2    Philip    M      16    72.0      150.0
 
  2    Philip    M      16    72.0      150.0
Line 868: Line 862:
  
 
* Predecessor: [[Routine_CxInclude]], a derivative work of the [[SmryEachVar_A_Data_Review_Suite]] routine CallXinc.
 
* Predecessor: [[Routine_CxInclude]], a derivative work of the [[SmryEachVar_A_Data_Review_Suite]] routine CallXinc.
* Companion: [[Macro_CallMacr]]  
+
* Companion: [[Macro_CallMacr]]
 
* data review: [[Macro_Invalid_for_Data_Review]]
 
* data review: [[Macro_Invalid_for_Data_Review]]
 
* [[SmryEachVar_A_Data_Review_Suite]]
 
* [[SmryEachVar_A_Data_Review_Suite]]

Revision as of 19:23, 10 October 2016

Companion: Macro_CallMacr

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(&text);
note: tokens: sex: m count: 10 percent: 52

CallText

note: published in MWSUG-2016, Tools of the Trade, paper TT06

 /* name: <UNC>\SAS-site\macros\calltext.sas
  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: delimiter, 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))
           ,hex16   = 1 :: default, convert numeric 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 :: 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: CALLTEXT used real time  0:00:00.016
-----------------------------------------------------------
usage example:
PROC freq data   = sashelp.class;
          tables   sex / noprint
             out = list_values;
run;*necessary;
DATA %calltext(data = list_values
              ,text = %nrstr(work.sex_&sex)
              );*end of data statement;
do until(endofile);
   set sashelp.class  end = endofile;
   %calltext(data      = list_values
            ,delimiter = %nrstr(else)
            ,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 end = endoFile;
MPRINT(CALLTEXT): if Sex eq "F" then output work.sex_F;
MPRINT(CALLTEXT): else
MPRINT(CALLTEXT): if Sex eq "M" then output work.sex_M;
25        end;
26     stop;
27     run;
NOTE: There were 19 obs read from data set SASHELP.CLASS
NOTE: The data set WORK.sex_F has  9 obs and 5 variables
NOTE: The data set WORK.sex_M has 10 obs and 5 variables
--------------------------------------------------------
DateTime: 2016-09-21 7:14:10 AM
word count:       words:  696
                  lines:  159
characters(no   spaces): 4610
characters(with spaces): 6643
****** ...................... */
%MACRO calltext
        (data     = sashelp.class
        ,text     = %nrstr(%put note: name:&name sex=&sex;)
        ,delimiter= /* %nrstr(else) */
        ,global   = 0 /* make mvars global? */
        ,hex16    = 1 /* convert numerics to hex16? */
        ,testing  = 0
        ,unquote  = 1 /* write notes to log? */
)/ des =
'site: assemble mvar assignment statement(s), unquote text'
 /** * store source /* */
;/**** NOTE: _*: avoid name collisions w/data set vars ***/
%local _delimiter _global _hex16 _text _testing _unquote
       _dsid _rc  _obs _n_obs    _var  _n_vars
       _name _num _type          _time_start _time_end;
%let _testing = %eval(not(0 eq &testing)
        or(    %sysfunc(getoption(mprint))  eq MPRINT
           and %sysfunc(getoption(source2)) eq SOURCE2));
%let _time_start= %sysfunc(datetime(),hex16);
%let _delimiter = &delimiter;
%let _global    = %eval(not(0 eq &global));
%let _hex16     = %eval(not(0 eq &hex16));
%let _text      = &text;
%let _unquote   = %eval(not(0 eq &unquote));
 
%**  description: assertions;
%**  purpose    : if fail then exit;
%if  not(%sysfunc(exist(&data))) %then %do;
     %put Err%str()or &sysmacroname: not exist(&data);
     %return;
     %end;
%let _dsid   = %sysfunc(open (&data       ));
%let _n_obs  = %sysfunc(attrn(&_dsid,nobs ));
%let _n_vars = %sysfunc(attrn(&_dsid,nvars));
%put info: &sysmacroname &=data &=_n_obs &=_n_vars;
%if  not &_n_obs or not &_n_vars %then %do;
     %put Err%str()or &sysmacroname exit: not(nobs and vars);
     %goto close_exit;
     %end;
 
%** description: read data;
%** purpose    : make macro variable assignment(s), submit;
%do _obs = 1 %to &_n_obs;%*** fetchobs==read row;
    %let _rc       = %sysfunc(fetchobs(&_dsid,&_obs ));
    %do _var = 1 %to &_n_vars;
        %let _name = %sysfunc(varname (&_dsid,&_var ));
        %let _num  = %sysfunc(varnum  (&_dsid,&_name));
        %let _type = %sysfunc(vartype (&_dsid,&_num ));
        %if &_global %then %global &_name;
        %else              %local  &_name;
        %** assign: for type=C: value, type=N: hex16(value);
        %if   &_type eq C
           or(&_type eq N and not &_hex16) %then
              %let &_name = %left(%sysfunc(
                       getvar&_type(&_dsid,&_num)));
        %else %let &_name = %left(%sysfunc(putn(
              %sysfunc(getvar&_type(&_dsid,&_num)),hex16)));
        %if &_testing or &_global %then
            %put echo: &_name=&&&_name;
        %end;
 
    %if not &_testing and &_unquote %then
        %put &sysmacroname output: %cmpres(%unquote(&_text));
    %*** submit: note! no ending semicolon!;
    %unquote(&_text)
 
    %if %length(&_delimiter) and &_obs lt &_n_obs %then %do;
        %if not &_testing and &_unquote %then
            %put &sysmacroname output: %unquote(&_delimiter);
        %unquote(&_delimiter)
        %end;
    %end;
%if &_testing %then %put _local_;
 
%close_exit: %let _rc       = %sysfunc(close(&_dsid));
             %let _time_end = %sysfunc(datetime(),hex16);
%put info: &sysmacroname used real time %sysfunc
           (putn(&_time_end.x-&_time_start.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)