BookmarkSubscribeRSS Feed
Squashman
Calcite | Level 5

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 -----------------------                                 

8 REPLIES 8
data_null__
Jade | Level 19

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.

Squashman
Calcite | Level 5

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 */

         ;

data_null__
Jade | Level 19

you need two dots.  &clen..

Squashman
Calcite | Level 5

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.

data_null__
Jade | Level 19

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

Tom
Super User Tom
Super User

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..)

Peter_C
Rhodochrosite | Level 12

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

Squashman
Calcite | Level 5

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.

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 8 replies
  • 3439 views
  • 0 likes
  • 4 in conversation