/** @file @brief Generates the SAS statements that create Data Controller derived variables @details Derived (computed) variables are configured in MPE_DERIVED. Each row defines one variable, which is created in a DATA step view ahead of the filter, so that it can be filtered on in the EDIT screen. The engine lives in @sasjs/core as mp_derivedvars - this macro only supplies what is specific to Data Controller: the control table name, the bitemporal filter that picks the current version of a row, and the list of names that belong to the metadata and may not be used as a variable. The macro writes the generated statements to a fileref, so that callers can compose them into a view: %mpe_derived(libds=&libds,dclib=&mpelib,outref=dercode) data work.vw_derived / view=work.vw_derived; set &libds; %include dercode; run; Alternatively, pass outview= and the macro will build the view itself. The filter must be applied by the caller, in the step that reads the view: data out; set work.vw_derived; where %inc filtref;; run; A WHERE statement applies to the data set named on the SET statement, so it cannot reference a variable that is created in the same data step. Applying it to the view puts the derived variables on the input, which is what makes them filterable. Each statement block is of the form: attrib REGION length=$21 label='REGION=' format=$21.; REGION = ; Type and length are declared by the administrator, so the result is deterministic. VAR_LABEL is optional: when it is missing or blank the label is the variable name, an equals sign and the expression, otherwise the configured label is used as given. VAR_DEPS lists every input the expression uses - physical columns and derived variables alike. The statements are generated in dependency order, so a derived variable may build on another one without a sequence number being maintained. A cycle is rejected. Semicolons, macro triggers and comments are rejected, so a row can only ever be an expression. A derived variable may not reuse the name of a physical column, and may not reference itself: an intra-row calculation would imply a retained value, which depends on the order rows happen to arrive in.

SAS Macros

@li mp_derivedvars.sas @li mp_abort.sas @param [in] libds= The target table (libref.dataset, lib must be assigned) @param [in] dclib= The Data Controller control library @param [out] outref= (0) Fileref to receive the generated statements @param [out] outvars= (work.derived_vars) Dataset of derived variable names @param [in] outview= (0) Optional two-level name for the derived view @version 9.2 @author 4GL Apps Ltd @copyright 4GL Apps Ltd. This code may only be used within Data Controller and may not be re-distributed or re-sold without the express permission of 4GL Apps Ltd. **/ %macro mpe_derived(libds=, dclib=, outref=0, outvars=work.derived_vars, outview=0 ); %local reserved; /* the only name that has to be refused outright - the metadata columns of the target table are physical columns, so the engine's collision check covers them whatever MPE_TABLES calls them */ %let reserved=%str(_____DELETE__THIS__RECORD_____); %mp_abort(iftrue= (%length(&libds)=0 or %length(&dclib)=0) ,mac=&sysmacroname ,msg=%str(Missing: libds dclib) ) %mp_derivedvars( libds=&libds ,control=&dclib..mpe_derived ,where=%str(&dc_dttmtfmt lt tx_to and active=1) ,outref=&outref ,outvars=&outvars ,outview=&outview ,reserved=&reserved ) %mend mpe_derived;