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 -----------------------
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.
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 */
;
you need two dots. &clen..
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.
Put in two dots and if you get an error in the log post it here.
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..)
Check whether &clen has leading blanks. That might explain a failure.
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 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.