Hello!
I have written a macro which contains no errors or warnings but it is not outputting straightforward proc means and freqs inside it. I checked for imbalance in quotes, etc and didn't see. I also checked and build it up slowly. Basically the output of the macro only outputs to right before the 'data _null_' part and then nothing else outputs. Thank you for any advice.
Below is my macro and macro call (afterwards I post the log):
%macro codebook(lib=,ds=);
%if &lib=BLANK|&ds=BLANK %then %do;
%put &=lib;
%put &=ds;
%abort;
%end;
ods select variables;
proc contents data=&lib..&ds. out=_contents_ ; run;
proc format; value tfmt 1='NUM' 2='CHAR'; run;
data _null_;
set _contents_ end=last;
call symput("vname"||strip(put(_n_,best.)), strip(name));
call symput("vtype"||strip(put(_n_,best.)), strip(put(type,tfmt.)));
call symput("vlabel"||strip(put(_n_,best.)), strip(label));
if last then call symput("nVars",strip(put(_n_,best.)));
run;
%do j = 1 %to &nVars.;
title1 "Analysis of &&vlabel&j (Variable=%upcase(&&vname&j.)) ";
%if %upcase(&&vtype&j)='NUM' %then %do;
proc means data=&lib.&ds.;
var &&vname&j.;
run;
%end;
%else %if %upcase(&&vtype&j)='CHAR' %then %do;
proc freq data=&lib..&ds.;
tables &&vname&j.;
run;
%end;
%end;
%mend;
%codebook(lib=out,ds=adsl) ;
Below is my log: You can see that the output stops after the '_null_' section.
OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
NOTE: ODS statements in the SAS Studio environment may disable some output features.
73
74
75 %macro codebook(lib=,ds=);
76
77 %if &lib=BLANK|&ds=BLANK %then %do;
78 %put &=lib;
79 %put &=ds;
80 %abort;
81 %end;
82
83
84 ods select variables;
85 proc contents data=&lib..&ds. out=_contents_ ; run;
86 proc format; value tfmt 1='NUM' 2='CHAR'; run;
87
88 data _null_;
89 set _contents_ end=last;
90
91 call symput("vname"||strip(put(_n_,best.)), strip(name));
92 call symput("vtype"||strip(put(_n_,best.)), strip(put(type,tfmt.)));
93 call symput("vlabel"||strip(put(_n_,best.)), strip(label));
94
95 if last then call symput("nVars",strip(put(_n_,best.)));
96 run;
97
98
99 %do j = 1 %to &nVars.;
100 title1 "Analysis of &&vlabel&j (Variable=%upcase(&&vname&j.)) ";
101 %if %upcase(&&vtype&j)='NUM' %then %do;
102 proc means data=&lib.&ds.;
103 var &&vname&j.;
104 run;
105 %end;
106
107 %else %if %upcase(&&vtype&j)='CHAR' %then %do;
108
109 proc freq data=&lib..&ds.;
110 tables &&vname&j.;
111 run;
112 %end;
113 %end;
114
115 %mend;
116
117
118 %codebook(lib=out,ds=adsl);
Output Added:
-------------
Name: Variables
Label: Variables
Template: Base.Contents.Variables
Path: Contents.DataSet.Variables
-------------
NOTE: The data set WORK._CONTENTS_ has 13 observations and 41 variables.
NOTE: PROCEDURE CONTENTS used (Total process time):
real time 0.08 seconds
cpu time 0.09 seconds
NOTE: Format TFMT is already on the library WORK.FORMATS.
NOTE: Format TFMT has been output.
NOTE: PROCEDURE FORMAT used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
NOTE: There were 13 observations read from the data set WORK._CONTENTS_.
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
119
120
121 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
133
Run it with a check to see if it enters the IF conditions.
%if %upcase(&&vtype&j)='NUM' %then %do;
%PUT Condition was Met on &&vtype&j;
proc means data=&lib.&ds.;
var &&vname&j.;
run;
%end;
And/or turn on the debugging options, re-run and post that log.
options mprint symbolgen mlogic;
Thanks for the de-bugging advice. I added both checks. Below is my log and I specifically looked at the end. I run through 13 variables as you can see it seems okay looping through the variable types. The very last line, however, I don't understand 'macro variable graphterm resolves to 138' ?:
SYMBOLGEN: Macro variable NVARS resolves to 13
MLOGIC(CODEBOOK): %DO loop beginning; index variable J; start value is 1; stop value is 13; by value is 1.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 1
SYMBOLGEN: Macro variable VLABEL1 resolves to Age
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 1
SYMBOLGEN: Macro variable VNAME1 resolves to AGE
MPRINT(CODEBOOK): title1 "Analysis of Age (Variable=AGE) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 1
SYMBOLGEN: Macro variable VTYPE1 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='NUM' is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 1
SYMBOLGEN: Macro variable VTYPE1 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='CHAR' is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 2; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 2
SYMBOLGEN: Macro variable VLABEL2 resolves to Description of Planned Arm
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 2
SYMBOLGEN: Macro variable VNAME2 resolves to ARM
MPRINT(CODEBOOK): title1 "Analysis of Description of Planned Arm (Variable=ARM) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 2
SYMBOLGEN: Macro variable VTYPE2 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='NUM' is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 2
SYMBOLGEN: Macro variable VTYPE2 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='CHAR' is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 3; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 3
SYMBOLGEN: Macro variable VLABEL3 resolves to Planned Arm Code
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 3
SYMBOLGEN: Macro variable VNAME3 resolves to ARMCD
MPRINT(CODEBOOK): title1 "Analysis of Planned Arm Code (Variable=ARMCD) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 3
SYMBOLGEN: Macro variable VTYPE3 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='NUM' is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 3
SYMBOLGEN: Macro variable VTYPE3 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='CHAR' is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 4; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 4
SYMBOLGEN: Macro variable VLABEL4 resolves to Country
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 4
SYMBOLGEN: Macro variable VNAME4 resolves to COUNTRY
MPRINT(CODEBOOK): title1 "Analysis of Country (Variable=COUNTRY) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 4
SYMBOLGEN: Macro variable VTYPE4 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='NUM' is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 4
SYMBOLGEN: Macro variable VTYPE4 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='CHAR' is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 5; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 5
SYMBOLGEN: Macro variable VLABEL5 resolves to Race
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 5
SYMBOLGEN: Macro variable VNAME5 resolves to RACE
MPRINT(CODEBOOK): title1 "Analysis of Race (Variable=RACE) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 5
SYMBOLGEN: Macro variable VTYPE5 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='NUM' is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 5
SYMBOLGEN: Macro variable VTYPE5 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='CHAR' is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 6; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 6
SYMBOLGEN: Macro variable VLABEL6 resolves to Age categorization
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 6
SYMBOLGEN: Macro variable VNAME6 resolves to agecat
MPRINT(CODEBOOK): title1 "Analysis of Age categorization (Variable=AGECAT) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 6
SYMBOLGEN: Macro variable VTYPE6 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='NUM' is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 6
SYMBOLGEN: Macro variable VTYPE6 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='CHAR' is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 7; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 7
SYMBOLGEN: Macro variable VLABEL7 resolves to Change in diastolic bp
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 7
SYMBOLGEN: Macro variable VNAME7 resolves to diabp_change
MPRINT(CODEBOOK): title1 "Analysis of Change in diastolic bp (Variable=DIABP_CHANGE) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 7
SYMBOLGEN: Macro variable VTYPE7 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='NUM' is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 7
SYMBOLGEN: Macro variable VTYPE7 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='CHAR' is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 8; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 8
SYMBOLGEN: Macro variable VLABEL8 resolves to Change in heart rate
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 8
SYMBOLGEN: Macro variable VNAME8 resolves to hr_change
MPRINT(CODEBOOK): title1 "Analysis of Change in heart rate (Variable=HR_CHANGE) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 8
SYMBOLGEN: Macro variable VTYPE8 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='NUM' is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 8
SYMBOLGEN: Macro variable VTYPE8 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='CHAR' is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 9; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 9
SYMBOLGEN: Macro variable VLABEL9 resolves to Numeric Result/Finding in Standard Units
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 9
SYMBOLGEN: Macro variable VNAME9 resolves to pcmax
MPRINT(CODEBOOK): title1 "Analysis of Numeric Result/Finding in Standard Units (Variable=PCMAX) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 9
SYMBOLGEN: Macro variable VTYPE9 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='NUM' is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 9
SYMBOLGEN: Macro variable VTYPE9 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='CHAR' is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 10; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 10
SYMBOLGEN: Macro variable VLABEL10 resolves to Highest Value
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 10
SYMBOLGEN: Macro variable VNAME10 resolves to pcmax2
MPRINT(CODEBOOK): title1 "Analysis of Highest Value (Variable=PCMAX2) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 10
SYMBOLGEN: Macro variable VTYPE10 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='NUM' is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 10
SYMBOLGEN: Macro variable VTYPE10 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='CHAR' is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 11; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 11
SYMBOLGEN: Macro variable VLABEL11 resolves to Change in systolic bp
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 11
SYMBOLGEN: Macro variable VNAME11 resolves to sysbp_change
MPRINT(CODEBOOK): title1 "Analysis of Change in systolic bp (Variable=SYSBP_CHANGE) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 11
SYMBOLGEN: Macro variable VTYPE11 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='NUM' is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 11
SYMBOLGEN: Macro variable VTYPE11 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='CHAR' is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 12; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 12
SYMBOLGEN: Macro variable VLABEL12 resolves to Unique Subject Identifier
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 12
SYMBOLGEN: Macro variable VNAME12 resolves to usubjid
MPRINT(CODEBOOK): title1 "Analysis of Unique Subject Identifier (Variable=USUBJID) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 12
SYMBOLGEN: Macro variable VTYPE12 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='NUM' is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 12
SYMBOLGEN: Macro variable VTYPE12 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='CHAR' is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 13; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 13
SYMBOLGEN: Macro variable VLABEL13 resolves to Change in weight
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 13
SYMBOLGEN: Macro variable VNAME13 resolves to wgt_change
MPRINT(CODEBOOK): title1 "Analysis of Change in weight (Variable=WGT_CHANGE) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 13
SYMBOLGEN: Macro variable VTYPE13 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='NUM' is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 13
SYMBOLGEN: Macro variable VTYPE13 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)='CHAR' is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 14; loop will not iterate again.
MLOGIC(CODEBOOK): Ending execution.
124
125
126 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
SYMBOLGEN: Macro variable GRAPHTERM resolves to
138
Hello @remainmack,
The quotes around the strings 'NUM' and 'CHAR' are incorrect in macro language. Just remove them.
Also, add the second period in &lib..&ds. in the PROC MEANS step.
Thank you both for the advice. I forgot about the quotes. Removing them, however, caused errors. So what I did was convert 'NUM' to NUM (error) and then to 1 since that is a numeric type. I did the same for CHAR renaming to 2 (after that error). I also added the second period as mentioned, but still the output remains stopped after the proc contents. The loops still look okay when I use 1 and 2 for those types. The NUM and CHAR with quotes removed, caused errors.
I posted the code and log again below.
Code:
options mprint symbolgen mlogic;
%macro codebook(lib=,ds=);
%if &lib=BLANK|&ds=BLANK %then %do;
%put &=lib;
%put &=ds;
%abort;
%end;
ods select variables;
proc contents data=&lib..&ds. out=_contents_ ; run;
proc format; value tfmt 1='NUM' 2='CHAR'; run;
data _null_;
set _contents_ end=last;
call symput("vname"||strip(put(_n_,best.)), strip(name));
call symput("vtype"||strip(put(_n_,best.)), strip(put(type,tfmt.)));
call symput("vlabel"||strip(put(_n_,best.)), strip(label));
if last then call symput("nVars",strip(put(_n_,best.)));
run;
%do j = 1 %to &nVars.;
title1 "Analysis of &&vlabel&j (Variable=%upcase(&&vname&j.)) ";
%if %upcase(&&vtype&j)=1 %then %do;
%PUT Condition was Met on &&vtype&j;
proc means data=&lib..&ds.;
var &vname;
run;
%end;
%else %if %upcase(&&vtype&j)=2 %then %do;
proc freq data=&lib..&ds.;
tables &vname;
run;
%end;
%end;
%mend;
%codebook(lib=out,ds=adsl) ;
Log:
1 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
SYMBOLGEN: Macro variable _SASWSTEMP_ resolves to /folders/myfolders/.sasstudio/.images/ab67408b-9085-47c6-aa5d-fd1ebb399085
SYMBOLGEN: Some characters in the above value which were subject to macro quoting have been unquoted for printing.
SYMBOLGEN: Macro variable GRAPHINIT resolves to
NOTE: ODS statements in the SAS Studio environment may disable some output features.
73
74 *************
75 project: BIOS 511
76
77 Name: lab-13-task-2-710929473-Task1.sas
78
79 Author: Alexandre Lockhart
80
81 Date: 2019-11-26
82
83 Purpose: Lab 13 Task 2 of BIOS 511. Implement codebook macro for ADSL and DM datasets.
84 *************;
85
86
87
88
89
90 %let root = /folders/myfolders/BIOS511;
91 %let lab = Lab-13;
92 %let dataPath = &root/Lab/&lab./Data;
SYMBOLGEN: Macro variable ROOT resolves to /folders/myfolders/BIOS511
SYMBOLGEN: Macro variable LAB resolves to Lab-13
93 %let macroPath = &root/Lab/&lab./Macros;
SYMBOLGEN: Macro variable ROOT resolves to /folders/myfolders/BIOS511
SYMBOLGEN: Macro variable LAB resolves to Lab-13
94
95
96 libname echo "&root./data/echo" access=read;
SYMBOLGEN: Macro variable ROOT resolves to /folders/myfolders/BIOS511
NOTE: Libref ECHO was successfully assigned as follows:
Engine: V9
Physical Name: /folders/myfolders/BIOS511/data/echo
97 libname out "&dataPath." access=read;
SYMBOLGEN: Macro variable DATAPATH resolves to /folders/myfolders/BIOS511/Lab/Lab-13/Data
NOTE: Libref OUT was successfully assigned as follows:
Engine: V9
Physical Name: /folders/myfolders/BIOS511/Lab/Lab-13/Data
SYMBOLGEN: Macro variable ROOT resolves to /folders/myfolders/BIOS511
SYMBOLGEN: Macro variable LAB resolves to Lab-13
98
99
100 %let outpath=&root/Lab/&lab./Output;
101
102
103 *ods pdf file='&outpath./tst.pdf';
104 options mprint symbolgen mlogic;
105 %macro codebook(lib=,ds=);
106
107 %if &lib=BLANK|&ds=BLANK %then %do;
108 %put &=lib;
109 %put &=ds;
110 %abort;
111 %end;
112
113
114 ods select variables;
115 proc contents data=&lib..&ds. out=_contents_ ; run;
116 proc format; value tfmt 1='NUM' 2='CHAR'; run;
117
118 data _null_;
119 set _contents_ end=last;
120
121 call symput("vname"||strip(put(_n_,best.)), strip(name));
122 call symput("vtype"||strip(put(_n_,best.)), strip(put(type,tfmt.)));
123 call symput("vlabel"||strip(put(_n_,best.)), strip(label));
124
125 if last then call symput("nVars",strip(put(_n_,best.)));
126 run;
127
128
129 %do j = 1 %to &nVars.;
130 title1 "Analysis of &&vlabel&j (Variable=%upcase(&&vname&j.)) ";
131 %if %upcase(&&vtype&j)=1 %then %do;
132
133 %PUT Condition was Met on &&vtype&j;
134
135 proc means data=&lib..&ds.;
136
137
138 var &vname;
139 run;
140 %end;
141
142 %else %if %upcase(&&vtype&j)=2 %then %do;
143
144 proc freq data=&lib..&ds.;
145 tables &vname;
146 run;
147 %end;
148 %end;
149
150 %mend;
151
152
153 %codebook(lib=out,ds=adsl);
MLOGIC(CODEBOOK): Beginning execution.
MLOGIC(CODEBOOK): Parameter LIB has value out
MLOGIC(CODEBOOK): Parameter DS has value adsl
SYMBOLGEN: Macro variable LIB resolves to out
SYMBOLGEN: Macro variable DS resolves to adsl
MLOGIC(CODEBOOK): %IF condition &lib=BLANK|&ds=BLANK is FALSE
MPRINT(CODEBOOK): ods select variables;
SYMBOLGEN: Macro variable LIB resolves to out
SYMBOLGEN: Macro variable DS resolves to adsl
MPRINT(CODEBOOK): proc contents data=out.adsl out=_contents_ ;
MPRINT(CODEBOOK): run;
Output Added:
-------------
Name: Variables
Label: Variables
Template: Base.Contents.Variables
Path: Contents.DataSet.Variables
-------------
NOTE: The data set WORK._CONTENTS_ has 13 observations and 41 variables.
NOTE: PROCEDURE CONTENTS used (Total process time):
real time 0.11 seconds
cpu time 0.10 seconds
MPRINT(CODEBOOK): proc format;
MPRINT(CODEBOOK): value tfmt 1='NUM' 2='CHAR';
NOTE: Format TFMT is already on the library WORK.FORMATS.
NOTE: Format TFMT has been output.
MPRINT(CODEBOOK): run;
NOTE: PROCEDURE FORMAT used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
MPRINT(CODEBOOK): data _null_;
MPRINT(CODEBOOK): set _contents_ end=last;
MPRINT(CODEBOOK): call symput("vname"||strip(put(_n_,best.)), strip(name));
MPRINT(CODEBOOK): call symput("vtype"||strip(put(_n_,best.)), strip(put(type,tfmt.)));
MPRINT(CODEBOOK): call symput("vlabel"||strip(put(_n_,best.)), strip(label));
MPRINT(CODEBOOK): if last then call symput("nVars",strip(put(_n_,best.)));
MPRINT(CODEBOOK): run;
NOTE: There were 13 observations read from the data set WORK._CONTENTS_.
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
SYMBOLGEN: Macro variable NVARS resolves to 13
MLOGIC(CODEBOOK): %DO loop beginning; index variable J; start value is 1; stop value is 13; by value is 1.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 1
SYMBOLGEN: Macro variable VLABEL1 resolves to Age
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 1
SYMBOLGEN: Macro variable VNAME1 resolves to AGE
MPRINT(CODEBOOK): title1 "Analysis of Age (Variable=AGE) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 1
SYMBOLGEN: Macro variable VTYPE1 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 1
SYMBOLGEN: Macro variable VTYPE1 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=2 is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 2; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 2
SYMBOLGEN: Macro variable VLABEL2 resolves to Description of Planned Arm
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 2
SYMBOLGEN: Macro variable VNAME2 resolves to ARM
MPRINT(CODEBOOK): title1 "Analysis of Description of Planned Arm (Variable=ARM) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 2
SYMBOLGEN: Macro variable VTYPE2 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 2
SYMBOLGEN: Macro variable VTYPE2 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=2 is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 3; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 3
SYMBOLGEN: Macro variable VLABEL3 resolves to Planned Arm Code
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 3
SYMBOLGEN: Macro variable VNAME3 resolves to ARMCD
MPRINT(CODEBOOK): title1 "Analysis of Planned Arm Code (Variable=ARMCD) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 3
SYMBOLGEN: Macro variable VTYPE3 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 3
SYMBOLGEN: Macro variable VTYPE3 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=2 is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 4; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 4
SYMBOLGEN: Macro variable VLABEL4 resolves to Country
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 4
SYMBOLGEN: Macro variable VNAME4 resolves to COUNTRY
MPRINT(CODEBOOK): title1 "Analysis of Country (Variable=COUNTRY) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 4
SYMBOLGEN: Macro variable VTYPE4 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 4
SYMBOLGEN: Macro variable VTYPE4 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=2 is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 5; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 5
SYMBOLGEN: Macro variable VLABEL5 resolves to Race
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 5
SYMBOLGEN: Macro variable VNAME5 resolves to RACE
MPRINT(CODEBOOK): title1 "Analysis of Race (Variable=RACE) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 5
SYMBOLGEN: Macro variable VTYPE5 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 5
SYMBOLGEN: Macro variable VTYPE5 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=2 is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 6; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 6
SYMBOLGEN: Macro variable VLABEL6 resolves to Age categorization
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 6
SYMBOLGEN: Macro variable VNAME6 resolves to agecat
MPRINT(CODEBOOK): title1 "Analysis of Age categorization (Variable=AGECAT) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 6
SYMBOLGEN: Macro variable VTYPE6 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 6
SYMBOLGEN: Macro variable VTYPE6 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=2 is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 7; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 7
SYMBOLGEN: Macro variable VLABEL7 resolves to Change in diastolic bp
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 7
SYMBOLGEN: Macro variable VNAME7 resolves to diabp_change
MPRINT(CODEBOOK): title1 "Analysis of Change in diastolic bp (Variable=DIABP_CHANGE) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 7
SYMBOLGEN: Macro variable VTYPE7 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 7
SYMBOLGEN: Macro variable VTYPE7 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=2 is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 8; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 8
SYMBOLGEN: Macro variable VLABEL8 resolves to Change in heart rate
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 8
SYMBOLGEN: Macro variable VNAME8 resolves to hr_change
MPRINT(CODEBOOK): title1 "Analysis of Change in heart rate (Variable=HR_CHANGE) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 8
SYMBOLGEN: Macro variable VTYPE8 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 8
SYMBOLGEN: Macro variable VTYPE8 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=2 is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 9; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 9
SYMBOLGEN: Macro variable VLABEL9 resolves to Numeric Result/Finding in Standard Units
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 9
SYMBOLGEN: Macro variable VNAME9 resolves to pcmax
MPRINT(CODEBOOK): title1 "Analysis of Numeric Result/Finding in Standard Units (Variable=PCMAX) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 9
SYMBOLGEN: Macro variable VTYPE9 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 9
SYMBOLGEN: Macro variable VTYPE9 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=2 is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 10; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 10
SYMBOLGEN: Macro variable VLABEL10 resolves to Highest Value
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 10
SYMBOLGEN: Macro variable VNAME10 resolves to pcmax2
MPRINT(CODEBOOK): title1 "Analysis of Highest Value (Variable=PCMAX2) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 10
SYMBOLGEN: Macro variable VTYPE10 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 10
SYMBOLGEN: Macro variable VTYPE10 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=2 is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 11; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 11
SYMBOLGEN: Macro variable VLABEL11 resolves to Change in systolic bp
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 11
SYMBOLGEN: Macro variable VNAME11 resolves to sysbp_change
MPRINT(CODEBOOK): title1 "Analysis of Change in systolic bp (Variable=SYSBP_CHANGE) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 11
SYMBOLGEN: Macro variable VTYPE11 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 11
SYMBOLGEN: Macro variable VTYPE11 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=2 is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 12; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 12
SYMBOLGEN: Macro variable VLABEL12 resolves to Unique Subject Identifier
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 12
SYMBOLGEN: Macro variable VNAME12 resolves to usubjid
MPRINT(CODEBOOK): title1 "Analysis of Unique Subject Identifier (Variable=USUBJID) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 12
SYMBOLGEN: Macro variable VTYPE12 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 12
SYMBOLGEN: Macro variable VTYPE12 resolves to CHAR
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=2 is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 13; loop will iterate again.
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 13
SYMBOLGEN: Macro variable VLABEL13 resolves to Change in weight
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 13
SYMBOLGEN: Macro variable VNAME13 resolves to wgt_change
MPRINT(CODEBOOK): title1 "Analysis of Change in weight (Variable=WGT_CHANGE) ";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 13
SYMBOLGEN: Macro variable VTYPE13 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable J resolves to 13
SYMBOLGEN: Macro variable VTYPE13 resolves to NUM
MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=2 is FALSE
MLOGIC(CODEBOOK): %DO loop index variable J is now 14; loop will not iterate again.
MLOGIC(CODEBOOK): Ending execution.
154
155
156
157
158 /*
159 %include "macroPath.\codebook.sas"
160
161 ods pdf file="&outputPath.\ADSL-CODEBOOK-PID.pdf" style=sasweb;
162 %codebook(lib=out,ds=adsl,maxVal=4);
163 ods pdf close;
164
165 ods pdf file="&outputPath.\ADSL-CODEBOOK-DM.pdf" styke=sasweb;
166 %codebook(lib=echo,ds=dm,maxVal=4);
167 ods pdf close;
168
169
170
171 */
172
173
174
175 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
SYMBOLGEN: Macro variable GRAPHTERM resolves to
187
SYMBOLGEN: Macro variable VTYPE7 resolves to NUM MLOGIC(CODEBOOK): %IF condition %upcase(&&vtype&j)=1 is FALSE SYMBOLGEN: && resolves to &.
Your conversion didn't work. Make sure to test each step when you make a change. Changing too many things at once makes things complicated.
Thank you everyone. I backed up and my output appears to be okay. I tried to add one feature to my proc freqs to finish. I am adding a parameter for the maximum number of unique values for a character variable for if the number of unique values for the variable is less than or equal to the parameter, a frequency analysis is included in the macro presenting data for all unique values of the variable in question. If the number of unique values is large than the parameter, then only the parameter most frequent values should be displayed. The default value of the parameter I am setting to 5 for now.
The issue I am having is 1) I don't know how to set both sides of the condition (greater or less than) for my third parameter and 2) set my default number within the macro (trying to set to 5).
%macro codebook(lib=,ds=,maxVal=);
%if &lib= BLANK | &ds = BLANK %then %do;
%put &=lib;
%put &=ds;
%abort;
%end;
ods select variables;
proc contents data=&lib..&ds. out=_contents_ ; run;
proc format;
value tfmt
1 = 'NUM'
2 = 'CHAR';
run;
data _null_;
set _contents_ end=last;
call symput('vname'||strip(put(_n_,best.)), strip(name));
call symput('vtype'||strip(put(_n_,best.)), strip(put(type,tfmt.)));
call symput('vlabel'||strip(put(_n_,best.)), strip(label));
if last then call symput('nVars',strip(put(_n_,best.)));
run;
%do j = 1 %to &nVars.;
title1 "Analysis of &&vlabel&j (Variable=%upcase(&&vname&j.)) ";
%if &&vtype&j=NUM %then %do;
%PUT Condition was Met on &&vtype&j;
proc means data=&lib..&ds.;
var &&vname&j.;
run;
%end;
%else %if &&vtype&j=CHAR %then %do;
proc freq data=&lib..&ds.;
tables &&vname&j./out=freqtab;
run;
%let printALL=YES;
data _null_;
set freqtab;
if _n_ > &maxVal. then
call symput('printAll','NO');
run;
%end;
%end;
%mend;
%codebook(lib=out,ds=adsl,maxVal=4) ;
Not a big fan of generating dozens (hundreds) of macro variables, but if you must why not just use PROC SQL to do it?
Why do you care whether the values of VTYPExxx is coded as 1 or NUM? Just right the code to use the value it has.
%macro codebook(lib=,ds=);
%local nvars j ;
%if 0=%length(&lib) or 0=%length(&ds) %then %do;
%put ERROR: Please provide both LIB and DS. &=lib &=ds ;
%end;
%else %do;
ods select variables;
title1 "Variables for &lib..&ds";
proc contents data=&lib..&ds. out=_contents_ ;
run;
proc sql noprint ;
select name,type,coalesce(label,name)
into :vname1-,:vtype1-,:vlabel1-
from _contents_
order by name
;
%let nvars=&sqlobs;
quit;
%do j = 1 %to &nVars.;
title1 "Analysis of &&vlabel&j (Variable=%upcase(&&vname&j.)) ";
%if %upcase(&&vtype&j)=1 %then %do;
proc means data=&lib..&ds.;
var &&vname&j.;
run;
%end;
%else %do;
proc freq data=&lib..&ds.;
tables &&vname&j.;
run;
%end;
%end;
%end;
%mend codebook;
And let's try it.
%codebook(lib=sashelp,ds=class(keep=age sex));
.
Thanks for the suggestion, Tom. You're right: I could use sql to do it. But it didn't solve my recent question. Since my latest question is pertaining to dealing with that third parameter, I will post a new thread to avoid confusion.
There's a lot of these out there already, perhaps finding an example that's close to what you want will help.
https://www.lexjansen.com/search/searchresults.php?q=codebook
You may also want to look at the NLEVELS option within PROC FREQ statement which tells you the number of levels so you don't have to figure it out yourself.
hI @remainmack
It is much easier to drop the macro altogether and do the same in a data step with Call Execute:
** NOTE: New code with stop statement ***
data have;
a = 1; b = 3; c = 'ole';
run;
%let lib = work;
%let ds = have;
data _null_; set have;
array num{*} _numeric_;
array char{*} _character_;
length thisvar $32;
do i = 1 to dim(num);
call vname(num{i},thisvar);
call execute ("proc means data=&lib..&ds; var " || trim(thisvar) || '; run;');
end;
do j = 1 to dim(char);
call vname(char{j},thisvar);
call execute ("proc freq data=&lib..&ds; tables " || trim(thisvar) || '; run;');
end;
stop;
run;
Regards
Erik
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.