From: Bill McKirgan on
On Apr 16, 11:09 am, Bill McKirgan <bill.mckir...(a)gmail.com> wrote:
> On Apr 16, 10:36 am, "data _null_;" <datan...(a)gmail.com> wrote:
>
>
>
>
>
> > On Apr 15, 9:42 pm, Bill McKirgan <bill.mckir...(a)gmail.com> wrote:
>
> > > On Apr 15, 9:40 pm, Bill McKirgan <bill.mckir...(a)gmail.com> wrote:
>
> > > > On Apr 15, 9:35 pm, Bill McKirgan <bill.mckir...(a)gmail.com> wrote:
>
> > > > > I'm stumped, but very close to the solution I see...at least I think
> > > > > so.
>
> > > > > I have a collection of metadata that I am trying to transform into SAS
> > > > > format statements.  The data are nicely organized, coming from an
> > > > > OpenClinica implementation of CDISC, and I am at the final stages of
> > > > > telling SAS how to write the lines of code that I want to save to text
> > > > > files for later use.
>
> > > > > The following sample is close to what I want (a series of valid proc
> > > > > format VALUE statements); however, the closing semicolon IS MISPLACED.
> > > > > So, here's my code:
>
> > > > > data _null_; set code_fmts;
>
> > > > >         if codelist_ordinal le 2 ; /* testing */
> > > > >         by codelist_ordinal;
>
> > > > >                 if _n_=1 then do;
> > > > >                         firstline='proc format ; ';
> > > > >                         put firstline;
> > > > >                 end;
>
> > > > >                 if first.codelist_ordinal then do;
> > > > >                         fmtnameline='value '||sasformatname;
> > > > >                         put fmtnameline;
> > > > >                 end;
>
> > > > >                 if last.codelist_ordinal then do;
> > > > >                         endvalue=';';
> > > > >                         put endvalue;
> > > > >                 end;
>
> > > > >                 lines= codedvalue || '="' ||trim(translatedtext)||'"';
> > > > >                 put lines;
> > > > > run;
>
> > > > > And here's the log...
>
> > > > > proc format ;
> > > > > value YES_NO
> > > > > 1  ="Yes"
> > > > > 0  ="No"
> > > > > .I ="NI"
> > > > > .A ="NA"
> > > > > .U ="UNK"
> > > > > ;
> > > > > .O ="OTH"
> > > > > value NEUROPAT
> > > > > 0  ="Grade0"
> > > > > 1  ="Grade1"
> > > > > 2  ="Grade2"
> > > > > 3  ="Grade3"
> > > > > 4  ="Grade4"
> > > > > .I ="NI"
> > > > > .A ="NA"
> > > > > .U ="UNK"
> > > > > ;
> > > > > .O ="OTH"
> > > > > NOTE: There were 5025 observations read from the data set
> > > > > WORK.CODE_FMTS.
> > > > > NOTE: DATA statement used (Total process time):
> > > > >       real time           0.00 seconds
> > > > >       cpu time            0.00 seconds
>
> > > > > Of course I want the semicolon to FOLLOW the last value in each VALUE
> > > > > statement.
>
> > > > > Can someone suggest a way for me to fix this?
>
> > > > > Thank you in advance.
>
> > > > > Bill McKirgan
>
> > > > Doah...nevermind
>
> > > > data _null_; set code_fmts;
>
> > > >         if codelist_ordinal le 2 ; /* testing */
> > > >         by codelist_ordinal;
>
> > > >                 if _n_=1 then do;
> > > >                         firstline='proc format ; ';
> > > >                         put firstline;
> > > >                 end;
>
> > > >                 if first.codelist_ordinal then do;
> > > >                         fmtnameline='value '||sasformatname;
> > > >                         put fmtnameline;
> > > >                 end;
> > > > /* fixed by putting LINES= here *******/
> > > >                 lines= codedvalue || '="' ||trim(translatedtext)||'"';
> > > >                 put lines;
> > > >                 if last.codelist_ordinal then do;
> > > >                         endvalue=';';
> > > >                         put endvalue;
> > > >                 end;
>
> > > > run;
>
> > > > proc format ;
> > > > value YES_NO
> > > > 1  ="Yes"
> > > > 0  ="No"
> > > > .I ="NI"
> > > > .A ="NA"
> > > > .U ="UNK"
> > > > ;
> > > > .O ="OTH"
> > > > value NEUROPAT
> > > > 0  ="Grade0"
> > > > 1  ="Grade1"
> > > > 2  ="Grade2"
> > > > 3  ="Grade3"
> > > > 4  ="Grade4"
> > > > .I ="NI"
> > > > .A ="NA"
> > > > .U ="UNK"
> > > > ;
> > > > .O ="OTH"
> > > > NOTE: There were 5025 observations read from the data set
> > > > WORK.CODE_FMTS.
> > > > NOTE: DATA statement used (Total process time):
> > > >       real time           0.00 seconds
> > > >       cpu time            0.00 seconds
>
> > > And this is what I'm now seeing in the log...not what was in post 1
> > > and #2
>
> > > proc format ;
> > > value YES_NO
> > > 1  ="Yes"
> > > 0  ="No"
> > > .I ="NI"
> > > .A ="NA"
> > > .U ="UNK"
> > > .O ="OTH"
> > > ;
> > > value NEUROPAT
> > > 0  ="Grade0"
> > > 1  ="Grade1"
> > > 2  ="Grade2"
> > > 3  ="Grade3"
> > > 4  ="Grade4"
> > > .I ="NI"
> > > .A ="NA"
> > > .U ="UNK"
> > > .O ="OTH"
> > > ;
>
> > > ...sorry folks....it's getting late here- Hide quoted text -
>
> > > - Show quoted text -
>
> > Good to see you got the program working.  Why not use a CONTROL data
> > set with CNTLIN option in proc format to create the formats?
>
> > Of course the way you are doing it is exactly the same way it is done
> > at many PHARMAS.  In fact the code is probably %INC in each an every
> > program.   I also used the program when I want to "browse the
> > formats", but %INCing every time is somewhat inefficient.
>
> > For the code GEN I would suggest that you at least take advantage of
> > the QUOTE function.  QUOTE will accommodate quotes in the values.
> > Also, I would take more advantage of the PUT statements features to
> > make the GENed code look “nicer”.
>
> > For example:
>
> > data fmts;
> >    infile datalines dsd;
> >    informat codelist_ordinal codedvalue translatedtext $32.;
> >    input codelist_ordinal codedvalue translatedtext;
> >    datalines4;
> > NEUROPAT,.A,NA
> > NEUROPAT,.I,NI
> > NEUROPAT,.O,OTH
> > NEUROPAT,.U,UNK
> > NEUROPAT,0,Grade0
> > NEUROPAT,1,Grade"1
> > NEUROPAT,2,Grade2
> > NEUROPAT,3,Grade3
> > NEUROPAT,4,Grade4
> > YES_NO,.A,NA
> > YES_NO,.I,NI
> > YES_NO,.O,OTH
> > YES_NO,.U,UNK Ya'll
> > YES_NO,0,No
> > YES_NO,1,Yes
> > $TRT,A,Placebo
> > $TRT,B,Active
> > ;;;;
> >    run;
> > data _null_;
> >    file log column=c;
> >    put 'proc format;';
> >    do until(eof);
> >       do until(last.codelist_ordinal);
> >          set fmts end=eof;
> >          by notsorted codelist_ordinal;
> >          if first.codelist_ordinal then do;
> >             type = ifC(codelist_ordinal eq: '$','C','N');
> >             put +3 'value ' codelist_ordinal;
> >             end;
> >          select(type);
> >             when('C') put +6 codedvalue :$quote32.  @;
> >             when('N') put +6 codedvalue @;
> >             end;
> >          put @(max(c,10)) ' = ' translatedtext :$quote258.;
> >          end;
> >       put +6 ';' /;
> >       end;
> >    put +3 'Run;';
> >    stop;
> >    run;- Hide quoted text -
>
> > - Show quoted text -
>
> Thanks Data _Null_,
>
> The example you provided is much nicer than what I was developing.  It
> was easy for me to change it to route the ouput to a file I can %INC,
> and I just switched the VALUE to SASFORMATNAME to get the desired
> format names instead of the CODELIST_ORDINAL number.
>
> data _null_;
>    file "&LISTPATH.\my_SAS_FORMAT_STATEMENTS.SAS"  column=c;
>    put 'proc format;';
>    do until(eof);
>       do until(last.codelist_ordinal);
>          set CODE_fmts end=eof;
>          by notsorted codelist_ordinal;
>          if first.codelist_ordinal then do;
>             type = ifC(codelist_ordinal eq: '$','C','N');
>             put +3 'value ' SASFORMATNAME;
>             end;
>          select(type);
>             when('C') put +6 codedvalue :$quote32.  @;
>             when('N') put +6 codedvalue @;
>             end;
>          put @(max(c,10)) ' = ' translatedtext :$quote258.;
>          end;
>       put +6 ';' /;
>       end;
>    put +3 'Run;';
>    stop;
>    run;
>
> This is very helpful and will allow me to quickly get some important
> work done.  Later I will go back and work in applying the more
> efficient solution you recommend using a CONTROL dataset.  I will in
> fact be doing the opposite by making the format catalog file and then
> use CTNLOUT to create the control dataset that will be updated as our
> study evolves.  At least that's my plan for now.
>
> Thanks for your ideas and for the super-elegant code example.
>
> --Bill McKirgan- Hide quoted text -
>
> - Show quoted text -


Ah...one more tweak....to get the TYPE= triggering correctly! Mr
_Null_ did you leave it a bit ragged for me to better learn from? I
like to think so. Thanks again. I am learning some neat tricks here
and am grateful for what you've shared.

data _null_;
file "&LISTPATH.\my_SAS_FORMAT_STATEMENTS.SAS" column=c;
put 'proc format;';
do until(eof);
do until(last.codelist_ordinal);
set CODE_fmts end=eof;
by notsorted codelist_ordinal;
if first.codelist_ordinal then do;
type = ifC(SASFORMATNAME eq: '$','C','N');
put +3 'value ' SASFORMATNAME;
end;
select(type);
when('C') put +6 codedvalue :$quote32. @;
when('N') put +6 codedvalue @;
end;
put @(max(c,10)) ' = ' translatedtext :$quote258.;
end;
put +6 ';' /;
end;
put +3 'Run;';
stop;
run;