DATA Step, Macro, Functions and more

INFILE Length=

Reply
Occasional Contributor
Posts: 13

INFILE Length=

Working with SAS 9.2 on z/OS.

I have a SAS program that uses the FILE FILEVAR option to split a file based on the variable changing in the input.  We output the entire record from the infile to the output files and name the output files with the variable name.  We work with fixed length files and the variable I am splitting on will always be in position 1086 for 7 bytes but the length of the input file may change depending on the clients data.  Because of this I have to change the record length in 3 different spots of my SAS program every time I run it.  I would rather not have to change it every time so I have been trying to use the INFILE Length= to create a global variable to use with the INPUT statement, the LRECL when allocating the file names and the put statement when outputting the file.  The global variable works fine for the macro to define the LRECL when allocating the file names but it does not work when defining my input or with the put statement on the output.

Here is my working code without trying to use the global variable with INFILE Length=.  I am trying to figure out how to make the 2230 dynamic based on the input record length.

------ begin code -----

**********************************************************************;

**  FILE IN, INPUT, GET FIRST PART OF OUTPUT FILENAME               **;

**********************************************************************;

data orig ;

   format fname $44.;

   infile filein filename = fname ;

   input

      @1086  splitvar   $7.

      @1     orecord    $char2230.

      ;

   if _n_ = 1 then do;

      format infnme          $44. ;

      infnme       = fname;

      rfile        = reverse(compress(infnme));

      efile        = index(rfile,'.') ;

      lfile        = length(infnme);

      call symput('ifile',substr(compress(infnme), 1, lfile - efile));

   end ;

run;

**********************************************************************;

**  GET ONE OF EACH SPLIT VARIABLE FOR ALLOCATING DATASETS          **;

**********************************************************************;

proc sort data = orig NODUPKEY out=mkey ;

   by splitvar;

run;

**********************************************************************;

**  MACRO THAT DELETES AND ALLOCATES THE DATASETS                   **;

**********************************************************************;

%macro allocate(flref,mfile);

   filename &flref "&mfile."

      disp=(mod,delete) ;

   run;

   filename &flref "&mfile."

      disp=(new,catlg,delete)

      space=(CYL,(250,150),RLSE) unit=sms

      mgmtclas=list90

      recfm=fb lrecl=2230 blksize=0;

   run;

%mend allocate;

**********************************************************************;

**  DATA STEP THAT CALLS THE MACRO TO ALLOCATE DATASETS             **;

**********************************************************************;

data _null_;

   set mkey ;

      mfile = compress("&ifile"||'.W'|| splitvar);

      flref = compress('W' || splitvar);

      call execute('%allocate('||flref||','||mfile||')');

run;

**********************************************************************;

**  SORT DATA BEFORE FILE OUTPUT                                    **;

**********************************************************************;

proc sort data = orig ;

   by splitvar;

run;

**********************************************************************;

**  OUTPUT AND SPLIT THE FILES                                      **;

**********************************************************************;

data _null_;

   set orig ;

      mfile = compress("&ifile"||'.W'|| splitvar);

      flref = compress('W' || splitvar);

      file flref filevar=mfile;

      put

         @1    orecord $char2230.

         ;

run;

-------- end of code -------

One way I have been able to get the INPUT to work was write out the data step to TEMP and then use INCLUDE to bring that file back in to define my input but this just seems kind of hokey and too much coding.  I would think there has to be a simpler way then doing this.  This basically makes me create 3 DATA steps.  One data step to get the INFILE LENGTH.  A 2nd data step to Create the temp file and the resulting temp file is the 3rd data step included back into the program.

--------- begin test code ----------------

data _null;                                                          

   format inlen 4. ;                                                 

   format fname $44.;                                                

   infile filein filename = fname length = inlen obs=1 ;             

   input ;                                                           

      format reclen 4. ;                                             

      format infnme          $44. ;                                  

      reclen = inlen ;                                               

      infnme       = fname;                                          

      rfile        = reverse(compress(infnme));                      

      efile        = index(rfile,'.') ;                              

      lfile        = length(infnme);                                 

      call symput('ifile',substr(compress(infnme), 1, lfile - efile));                          

      call symput('clen',trim(left(reclen)));                           

run;                                                                 

                                                                     

filename pgm temp;                                                   

data _null_;                                                    

   clen = &clen.;                                               

   record = compress('¬¬¬¬¬¬@001¬¬¬orecord¬$char' || clen || '.');

   record =translate(record,' ','¬');                           

   file pgm;                                                    

      put 'data orig;';                                         

      put 'infile filein;';                                     

      put 'input';                                              

      put '@1086 splitvar  $7.';                                

      put record;                                               

      put ';';                                                  

      put 'run;';                                               

run;                                                            

                                                                

%include pgm;                

--------------- end of test code -----------------------                                 

Respected Advisor
Posts: 3,799

Re: INFILE Length=

Posted in reply to Squashman

Can you just add a data step to read one record from the file with LENGTH= option and put that value into a macro variable and use it in all the red spots.

Or perhaps just use JFCB infile statement option to read the LRECL for the file.  I'm about 25 years out from MVS or what ever it is called now so you're on your own there.

Occasional Contributor
Posts: 13

Re: INFILE Length=

Posted in reply to data_null__

No. The global variable works fine for the macro to define the LRECL when allocating the file names but it does not work when defining my input or with the put statement on the output.

I have been unable to get the Macro variable to work with the INPUT or PUT statements.

input

      @1086  splitvar   $7.

      @1     orecord    $char&clen/*does not work */

      ;

put

         @1    orecord $char&clen. /*does not work */

         ;

Respected Advisor
Posts: 3,799

Re: INFILE Length=

Posted in reply to Squashman

you need two dots.  &clen..

Occasional Contributor
Posts: 13

Re: INFILE Length=

Posted in reply to data_null__

Pretty sure I remember trying with 2 dots as well because are other SAS programmer who works here mentioned that to me as well.  She has been programming SAS for 20 years and she has not been able to figure it out as well.

Respected Advisor
Posts: 3,799

Re: INFILE Length=

Posted in reply to Squashman

Put in two dots and if you get an error in the log post it here.

Super User
Super User
Posts: 7,038

Re: INFILE Length=

Posted in reply to Squashman

If $CHAR&clen.. doesn't work try wrapping it in a %UNQUOTE().  Sometimes SAS parser can get confused and treat syntax like that as if there was a space or other token delimiter before the macro reference.

%unquote($CHAR&clen..)

Valued Guide
Posts: 2,177

Re: INFILE Length=

Check whether &clen has leading blanks. That might explain a failure.

Occasional Contributor
Posts: 13

Re: INFILE Length=

In my original code I was being anal and trimming leading and trailing spaces. That was all part of my call symput in my first data null step just to get the file length.

I have been on vacation this week so I will get back to this hopefully on Monday.

Ask a Question
Discussion stats
  • 8 replies
  • 674 views
  • 0 likes
  • 4 in conversation