%macro SQUEEZE( DSNIN /* name of input SAS dataset */
, DSNOUT /* name of output SAS dataset */
) ;
/* PURPOSE: create SAS dataset &DSNOUT using LENGTH */
/* statement for numeric vars that optimizes the */
/* variable to the fewest # of bytes needed */
/* to maintain the accuracy of the values */
/* contained in the variable */
/* */
/* macro variable SQZLENTH is created which is */
/* then invoked in a subsequent data step */
/* */
/* NOTE: only numeric variables are processed */
/* */
/* EXAMPLE OF USE: */
/* %SQUEEZE( DSNIN, DSNOUT ) */
%global SQUEEZE ;
%local I ;
%put *============================================* ;
%put | Beginning to SQUEEZE. | ;
%put | Please be patient because this process may | ;
%put | require a lot of execution time. | ;
%put *============================================* ;
%macro PUTNAME ;
/* PURPOSE: put variable names into SAS source code */
%do I = 1 %to &VAR_N ;
&&VAR&I
%end ;
%mend PUTNAME ;
%macro SQZLENTH ;
/* PURPOSE: create variable name-variable length pairs */
%do I = 1 %to &VAR_N ;
&&VAR&I &&VLEN&I
%end ;
%mend SQZLENTH ;
/***********************************************************/
/* ensure that DSNIN not same as DSNOUT */
/***********************************************************/
%if "&DSNIN" = "&DSNOUT"
%then %do ;
%put *================================================* ;
%put | ERROR from SQUEEZE: | ;
%put | Input Dataset has same name as Output Dataset. | ;
%put | Execution terminating forthwith. | ;
%put *================================================* ;
%goto L9999 ;
%end ;
%let VAR_N = 0 ;
/*##########################################################*/
/* begin executable code */
/*##########################################################*/
proc contents data=&DSNIN memtype=data noprint out=_cntnts_ ; run ;
data _null_ ;
set _cntnts_ ;
if type = 1 ;
var_no + 1 ;
/* create macro var containing final # of macro vars */
call symput( 'VAR_N', left( put( var_no, 4. ) ) ) ;
run ;
/* in case there are NO numeric vars in dataset, */
/* stop further processing */
%if "&VAR_N" = "0" %then %do ;
%put *==================================* ;
%put | ERROR from SQUEEZE: | ;
%put | No numeric variables in dataset. | ;
%put | Execution terminating forthwith. | ;
%put *==================================* ;
%goto L9999 ;
%end ;
/* put global macro names into environment for later retrieval */
%do I = 1 %to &VAR_N ;
%global VAR&I VLEN&I ;
%end ;
/* create macro vars containing variable name */
/* process variables of numeric type only */
data _null_ ;
set _cntnts_ ;
if type = 1 ;
var_no + 1 ;
call symput( 'VAR' || left( put( var_no, 5. )), name ) ;
run ;
/* compute min # bytes (3 = min length, for */
/* portability over platforms) */
data _null_ ;
set &DSNIN end=lastobs ;
array _length_ ( &VAR_N ) 3 _temporary_ ;
if _n_ = 1 then do i = 1 to &VAR_N ; _length_( i ) = 3 ; end ;
%do I = 1 %to &VAR_N ;
if &&VAR&I ne .
then do ;
if &&VAR&I ne trunc( &&VAR&I, 7 ) then _length_( &I )
= max( _length_( &I ), 8 ) ; else
if &&VAR&I ne trunc( &&VAR&I, 6 ) then _length_( &I )
= max( _length_( &I ), 7 ) ; else
if &&VAR&I ne trunc( &&VAR&I, 5 ) then _length_( &I )
= max( _length_( &I ), 6 ) ; else
if &&VAR&I ne trunc( &&VAR&I, 4 ) then _length_( &I )
= max( _length_( &I ), 5 ) ; else
if &&VAR&I ne trunc( &&VAR&I, 3 ) then _length_( &I )
= max( _length_( &I ), 4 ) ;
end ;
%end ;
if lastobs
then do ;
%do I = 1 %to &VAR_N ;
call symput( "VLEN&I", put( _length_( &I ), 1. )) ;
%end ;
end ;
run ;
proc datasets nolist ; delete _cntnts_ ; run ;
/* initialize SQZLENTH global macro var */
%let SQZLENTH = LENGTH ;
%do I = 1 %to &VAR_N ;
%if "&&VLEN&I" ne ""
%then %let SQZLENTH = &SQZLENTH %qtrim( &&VAR&I ) &&VLEN&I ;
%end ;
/* create global SQZLENTH variable containing */
/* var name-var length info */
%let SQZLENTH = &SQZLENTH %str( ; ) ;
/* apply SQZLENTH to incoming data, create output dataset */
data &DSNOUT ;
set &DSNIN ;
&SQZLENTH
run ;
%L9999:
%mend SQUEEZE ;
|