/** @file @brief Auto-generated file @details This file contains all the macros in a single file - which means it can be 'included' in SAS with just 2 lines of code: filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas"; %inc mc; The `build.py` file in the https://github.com/sasjs/core repo is used to create this file. @author Allan Bowe **/ options noquotelenmax; /** @file @brief Abort, ungracefully @details Will abort with a straightforward %abort if the condition is true.
&sysuserid
or SYS_COMPUTE_SESSION_OWNER
if it exists.
In a Stored Process session, &sysuserid
resolves to a system account (default=sassrv) and instead there are several
metadata username variables to choose from (_metauser, _metaperson
,_username, _secureusername). The OS account is represented by
_secureusername
whilst the metadata account is under
_metaperson
.
%let user= %mf_getUser();
%put &user;
@param type - do not use, may be deprecated in a future release
@return SYSUSERID (if workspace server)
@return _METAPERSON (if stored process server)
@return SYS_COMPUTE_SESSION_OWNER (if Viya compute session)
@version 9.2
@author Allan Bowe
**/
%macro mf_getuser(
)/*/STORE SOURCE*/;
%local user;
%if %symexist(_sasjs_username) %then %let user=&_sasjs_username;
%else %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %do;
%let user=&SYS_COMPUTE_SESSION_OWNER;
%end;
%else %if %symexist(_metaperson) %then %do;
%if %length(&_metaperson)=0 %then %let user=&sysuserid;
/* sometimes SAS will add @domain extension - remove for consistency */
/* but be sure to quote in case of usernames with commas */
%else %let user=%unquote(%scan(%quote(&_metaperson),1,@));
%end;
%else %let user=&sysuserid;
%quote(&user)
%mend mf_getuser;
/**
@file
@brief Retrieves a value from a dataset. If no filter supplied, then first
record is used.
@details Be sure to %quote()
your where clause. Example usage:
%put %mf_getvalue(sashelp.class,name,filter=%quote(age=15));
%put %mf_getvalue(sashelp.class,name);
%mf_getattrn()
.
%put Number of observations=%mf_nobs(sashelp.class);
getattrs=
is used.
maxobs
observations, enter an integer here.
@param [in] random_sample= (NO) Set to YES to generate a random sample of
data. Can be quite slow.
@param [in] showlog= (YES) Whether to show generated cards file in the SAS
log. Valid values:
@li YES
@li NO
@param [in] outencoding= Provide encoding value for file statement (eg utf-8)
@param [in] append= (NO) If NO then will rebuild the cards file if it already
exists, otherwise will append to it. Used by the mp_lib2cards.sas macro.
%mp_ds2cards()
macro.
Usage:
%mp_lib2cards(lib=sashelp
, outloc= C:\temp )
The output will be one cards file in the `outloc` directory per dataset in the
input `lib` library. If the `outloc` directory does not exist, it is created.
To create a single SAS file with the first 1000 records of each table in a
library you could use this syntax:
%mp_lib2cards(lib=sashelp
, outloc= /tmp
, outfile= myfile.sas
, maxobs= 1000
)
maxobs
observations
@version 9.2
@author Allan Bowe
**/
%macro mp_lib2cards(lib=
,outloc=%sysfunc(pathname(work)) /* without trailing slash */
,maxobs=max
,random_sample=NO
,outfile=0
)/*/STORE SOURCE*/;
/* Find the tables */
%local x ds memlist;
proc sql noprint;
select distinct lowcase(memname)
into: memlist
separated by ' '
from dictionary.tables
where upcase(libname)="%upcase(&lib)";
/* trim trailing slash, if provided */
%let outloc=%mf_trimstr(&outloc,/);
%let outloc=%mf_trimstr(&outloc,\);
/* create the output directory */
%mf_mkdir(&outloc)
/* create the cards files */
%do x=1 %to %sysfunc(countw(&memlist));
%let ds=%scan(&memlist,&x);
%mp_ds2cards(base_ds=&lib..&ds
,maxobs=&maxobs
,random_sample=&random_sample
%if "&outfile" ne "0" %then %do;
,append=YES
,cards_file="&outloc/&outfile"
%end;
%else %do;
,append=NO
,cards_file="&outloc/&ds..sas"
%end;
)
%end;
%mend mp_lib2cards;/**
@file
@brief Convert all data in a library to SQL insert statements
@details Gets list of members then calls the %mp_ds2inserts()
macro.
Usage:
%mp_getddl(sashelp, schema=work, fref=tempref)
%mp_lib2inserts(sashelp, schema=work, outref=tempref)
%inc tempref;
The output will be one file in the outref fileref.
work.mp_perflog
;
@version 9.2
@author Allan Bowe
@source https://github.com/sasjs/core
**/
%macro mp_perflog(label,libds=work.mp_perflog
)/*/STORE SOURCE*/;
%if not (%mf_existds(&libds)) %then %do;
data &libds;
length sysjobid $10 label $256 dttm 8.;
format dttm datetime19.3;
call missing(of _all_);
stop;
run;
%end;
proc sql;
insert into &libds
set sysjobid="&sysjobid"
,label=symget('label')
,dttm=%sysfunc(datetime());
quit;
%mend mp_perflog;/**
@file
@brief Enables previous observations to be re-instated
@details Remembers the last X observations by storing them in a hash table.
Is a convenience over the use of lag() or retain, when an entire observation
needs to be restored.
This macro will also restore automatic variables (such as _n_ and _error_).
Example Usage:
data example;
set sashelp.class;
calc_var=_n_*3;
%* initialise hash and save from PDV ;
%mp_prevobs(INIT,history=2)
if _n_ =10 then do;
%* fetch previous but 1 record;
%mp_prevobs(FETCH,-2)
put _n_= name= age= calc_var=;
%* fetch previous record;
%mp_prevobs(FETCH,-1)
put _n_= name= age= calc_var=;
%* reinstate current record ;
%mp_prevobs(FETCH,0)
put _n_= name= age= calc_var=;
end;
run;
Result:
Transaction Type | Key Behaviour | Column Behaviour |
---|---|---|
Deletes | The row is added to `&outDEL.` UNLESS it no longer exists in the base table, in which case it is added to `&errDS.` instead. | Deletes are unaffected by the addition or removal of non Primary-Key columns. |
Inserts |
Previously newly added rows are added to the `outADD` table UNLESS they
are present in the Base table. In this case they are added to the `&errDS.` table instead. |
Inserts are unaffected by the addition of columns in the Base Table (they are padded with blanks). Deleted columns are only a problem if they appear on the previous insert - in which case the record is added to `&errDS.`. |
Updates |
Previously modified rows are merged with base table values such that
only the individual cells that were _previously_ changed are re-applied.
Where the row contains cells that were not marked as having changed in
the prior transaction, the 'blanks' are filled with base table values in
the `outMOD` table. If the row no longer exists on the base table, then the row is added to the `errDS` table instead. |
Updates are unaffected by the addition of columns in the Base Table - the new cells are simply populated with Base Table values. Deleted columns are only a problem if they relate to a modified cell (`is_diff=1`) - in which case the record is added to `&errDS.`. |
tree=
parameter.
@param outds= the dataset to create that contains the list of stps.
@param mDebug= set to 1 to show debug messages in the log
@param showDesc= provide a non blank value to return stored process
descriptions
@param showUsageVersion= provide a non blank value to return the UsageVersion.
This is either 1000000 (type 1, 9.2) or 2000000 (type2, 9.3 onwards).
@returns outds dataset containing the following columns
- stpuri
- stpname
- treeuri
- stpdesc (if requested)
- usageversion (if requested)
@version 9.2
@author Allan Bowe
**/
%macro mm_getstps(
tree=
,name=
,outds=work.mm_getstps
,mDebug=0
,showDesc=
,showUsageVersion=
)/*/STORE SOURCE*/;
%local mD;
%if &mDebug=1 %then %let mD=;
%else %let mD=%str(*);
%&mD.put Executing mm_getstps.sas;
%&mD.put _local_;
data &outds;
length stpuri stpname usageversion treeuri stpdesc $256;
call missing (of _all_);
run;
%if %length(&tree)>0 %then %do;
/* get tree info */
%mm_gettree(tree=&tree,inds=&outds, outds=&outds, mDebug=&mDebug)
%if %mf_nobs(&outds)=0 %then %do;
%put NOTE: Tree &tree did not exist!!;
%return;
%end;
%end;
data &outds ;
set &outds(rename=(treeuri=treeuri_compare));
length treeuri query stpuri $256;
i+1;
%if %length(&name)>0 %then %do;
query="omsobj:ClassifierMap?@PublicType='StoredProcess' and @Name='&name'";
putlog query=;
%end;
%else %do;
query="omsobj:ClassifierMap?@PublicType='StoredProcess'";
%end;
%if &mDebug=1 %then %do;
putlog 'start' (_all_)(=);
%end;
do while(0&outds
) containing both the path
and uri.
Usage:
%mm_getTree(tree=/User Folders/sasdemo)
@param tree= the BIP Tree folder path or uri
@param outds= the dataset to create that contains the tree path & uri
@param inds= an optional input dataset to augment with treepath & treeuri
@param mDebug= set to 1 to show debug messages in the log
@returns outds dataset containing the following columns:
- treeuri
- treepath
@version 9.2
@author Allan Bowe
**/
%macro mm_getTree(
tree=
,inds=
,outds=work.mm_getTree
,mDebug=0
)/*/STORE SOURCE*/;
%local mD;
%if &mDebug=1 %then %let mD=;
%else %let mD=%str(*);
%&mD.put Executing mm_getTree.sas;
%&mD.put _local_;
data &outds;
length treeuri __parenturi __type __name $256 treepath $512;
%if %length(&inds)>0 %then %do;
set &inds;
%end;
__rc1=metadata_resolve("&tree",__type,treeuri);
if __type='Tree' then do;
__rc2=metadata_getattr(treeuri,"Name",__name);
treepath=cats('/',__name);
/* get parents */
do while (metadata_getnasn(treeuri,"ParentTree",1,__parenturi)>0);
__rc3=metadata_getattr(__parenturi,"Name",__name);
treepath=cats('/',__name,treepath);
treeuri=__parenturi;
end;
treeuri="&tree";
end;
else do;
__rc2=metadata_pathobj(' ',"&tree",'Folder',__type,treeuri);
treepath="&tree";
end;
&mD.put (_all_)(=);
drop __:;
if treeuri ne "" and treepath ne "" then output;
stop;
run;
%mend mm_getTree;/**
@file
@brief Creates a dataset with all metadata types
@details Usage:
%mm_gettypes(outds=types)
@param outds the dataset to create that contains the list of types
@returns outds dataset containing all types
@warning The following filenames are created and then de-assigned:
filename sxlemap clear;
filename response clear;
libname _XML_ clear;
@version 9.2
@author Allan Bowe
**/
%macro mm_gettypes(
outds=work.mm_gettypes
)/*/STORE SOURCE*/;
* use a temporary fileref to hold the response;
filename response temp;
/* get list of libraries */
proc metadata in=
'
%* compile macros ;
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
%* parmcards lets us write to a text file from open code ;
filename ft15f001 temp;
parmcards4;
%webout(FETCH)
%* do some sas, any inputs are now already WORK tables;
data example1 example2;
set sashelp.class;
run;
%* send data back;
%webout(OPEN)
%webout(ARR,example1) * Array format, fast, suitable for large tables ;
%webout(OBJ,example2) * Object format, easier to work with ;
%webout(CLOSE)
;;;;
%ms_createwebservice(path=/Public/app/common,name=appInit,code=ft15f001)
For more examples of using these web services with the SASjs Adapter, see:
https://github.com/sasjs/adapter#readme
@param [in] path= (0) The full SASjs Drive path in which to create the service
@param [in] name= Stored Program name
@param [in] desc= The description of the service (not implemented yet)
@param [in] precode= Space separated list of filerefs, pointing to the code
that needs to be attached to the beginning of the service (optional)
@param [in] code= (ft15f001) Space seperated fileref(s) of the actual code to
be added
@param [in] mDebug= (0) set to 1 to show debug messages in the log