Files
dc/sas/sasjs/macros/mpe_derived.sas
T
dc af31c36b67
Build / Build-and-ng-test (pull_request) Successful in 5m54s
Lighthouse Checks / lighthouse (pull_request) Successful in 21m52s
Build / Build-and-test-development (pull_request) Successful in 33m6s
fix(derived): only the delete marker is a reserved name
A table's metadata columns are named per table - VAR_TXFROM, VAR_TXTO and
VAR_PROCESSED in MPE_TABLES hold those names, and they can be anything (the
bitemporal demo table uses VER_FROM_DTTM and VER_TO_DTTM).  When they exist
they are physical columns of the target, so the engine's collision check
already refuses a VAR_NM that matches one, whatever it is called.

The hard-coded list treated three example names as special: it refused them on
tables that use other names, and told the reader something untrue about what
is reserved.
2026-10-21 22:23:10 +00:00

104 lines
3.6 KiB
SAS

/**
@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=<expression>' format=$21.;
REGION = <expression>;
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.
<h4> SAS Macros </h4>
@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;