From 68aee776d3a72a096ab4de27e3d301b4224f696c Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Mon, 10 May 2021 01:25:51 +0300 Subject: [PATCH] feat: new mp_ds2fmtds macro - converts a dataset to a new dataset where all values are the formatted values. Also added a test. --- all.sas | 98 ++++++++++++++++++++++++++++++++- base/mf_getuniquename.sas | 4 +- base/mp_ds2fmtds.sas | 95 ++++++++++++++++++++++++++++++++ tests/base/mp_ds2fmtds.test.sas | 28 ++++++++++ 4 files changed, 221 insertions(+), 4 deletions(-) create mode 100644 base/mp_ds2fmtds.sas create mode 100644 tests/base/mp_ds2fmtds.test.sas diff --git a/all.sas b/all.sas index cae10a2..3c39e4d 100644 --- a/all.sas +++ b/all.sas @@ -801,8 +801,8 @@ options noquotelenmax; %macro mf_getuniquename(prefix=MC); - &prefix.%substr(%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32-%length(&prefix)) -%mend;/** +&prefix.%substr(%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32-%length(&prefix)) +%mend mf_getuniquename;/** @file @brief Returns a userid according to session context @details In a workspace session, a user is generally represented by @@ -3254,6 +3254,100 @@ run; %mend;/** + @file + @brief Converts every value in a dataset to it's formatted value + @details Converts every value to it's formatted value. All variables will + become character, and will be in the same order. + + Usage: + + %mp_ds2fmtds(sashelp.cars,work.cards) + + @param [in] libds The library.dataset to be converted + @param [out] outds The dataset to create. + + @version 9.2 + @author Allan Bowe +**/ + +%macro mp_ds2fmtds(libds, outds +)/*/STORE SOURCE*/; + +/* validations */ +%if not %sysfunc(exist(&libds)) %then %do; + %put %str(WARN)ING: &libds does not exist; + %return; +%end; +%if %index(&libds,.)=0 %then %let libds=WORK.&libds; + +/* grab metadata */ +proc contents noprint data=&libds + out=_data_(keep=name type length format formatl formatd varnum); +run; +proc sort; + by varnum; +run; + +/* prepare formats and varnames */ +data _null_; + set &syslast end=last; + name=upcase(name); + /* fix formats */ + if type=2 or type=6 then do; + length fmt $49.; + if format='' then fmt=cats('$',length,'.'); + else if formatl=0 then fmt=cats(format,'.'); + else fmt=cats(format,formatl,'.'); + newlen=max(formatl,length); + end; + else do; + if format='' then fmt='best.'; + else if formatl=0 then fmt=cats(format,'.'); + else if formatd=0 then fmt=cats(format,formatl,'.'); + else fmt=cats(format,formatl,'.',formatd); + /* needs to be wide, for datetimes etc */ + newlen=max(length,formatl,24); + end; + /* 32 char unique name */ + newname='sasjs'!!substr(cats(put(md5(name),$hex32.)),1,27); + + call symputx(cats('name',_n_),name,'l'); + call symputx(cats('newname',_n_),newname,'l'); + call symputx(cats('len',_n_),newlen,'l'); + call symputx(cats('fmt',_n_),fmt,'l'); + call symputx(cats('type',_n_),type,'l'); + if last then call symputx('nobs',_n_,'l'); +run; + +/* clean up */ +proc sql; +drop table &syslast; + +%if &nobs=0 %then %do; + %put Dataset &libds has no columns! + data &outds; + set &libds; + run; + %return; +%end; + +data &outds; + /* rename on entry */ + set &libds(rename=( +%local i; +%do i=1 %to &nobs; + &&name&i=&&newname&i +%end; + )); +%do i=1 %to &nobs; + length &&name&i $&&len&i; + &&name&i=left(put(&&newname&i,&&fmt&i)); + drop &&newname&i; +%end; + if _error_ then call symputx('syscc',1012); +run; + +%mend mp_ds2fmtds;/** @file @brief Checks an input filter table for validity @details Performs checks on the input table to ensure it arrives in the diff --git a/base/mf_getuniquename.sas b/base/mf_getuniquename.sas index 8ccaec8..97e2a72 100644 --- a/base/mf_getuniquename.sas +++ b/base/mf_getuniquename.sas @@ -18,5 +18,5 @@ %macro mf_getuniquename(prefix=MC); - &prefix.%substr(%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32-%length(&prefix)) -%mend; \ No newline at end of file +&prefix.%substr(%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32-%length(&prefix)) +%mend mf_getuniquename; \ No newline at end of file diff --git a/base/mp_ds2fmtds.sas b/base/mp_ds2fmtds.sas new file mode 100644 index 0000000..5c18571 --- /dev/null +++ b/base/mp_ds2fmtds.sas @@ -0,0 +1,95 @@ +/** + @file + @brief Converts every value in a dataset to it's formatted value + @details Converts every value to it's formatted value. All variables will + become character, and will be in the same order. + + Usage: + + %mp_ds2fmtds(sashelp.cars,work.cards) + + @param [in] libds The library.dataset to be converted + @param [out] outds The dataset to create. + + @version 9.2 + @author Allan Bowe +**/ + +%macro mp_ds2fmtds(libds, outds +)/*/STORE SOURCE*/; + +/* validations */ +%if not %sysfunc(exist(&libds)) %then %do; + %put %str(WARN)ING: &libds does not exist; + %return; +%end; +%if %index(&libds,.)=0 %then %let libds=WORK.&libds; + +/* grab metadata */ +proc contents noprint data=&libds + out=_data_(keep=name type length format formatl formatd varnum); +run; +proc sort; + by varnum; +run; + +/* prepare formats and varnames */ +data _null_; + set &syslast end=last; + name=upcase(name); + /* fix formats */ + if type=2 or type=6 then do; + length fmt $49.; + if format='' then fmt=cats('$',length,'.'); + else if formatl=0 then fmt=cats(format,'.'); + else fmt=cats(format,formatl,'.'); + newlen=max(formatl,length); + end; + else do; + if format='' then fmt='best.'; + else if formatl=0 then fmt=cats(format,'.'); + else if formatd=0 then fmt=cats(format,formatl,'.'); + else fmt=cats(format,formatl,'.',formatd); + /* needs to be wide, for datetimes etc */ + newlen=max(length,formatl,24); + end; + /* 32 char unique name */ + newname='sasjs'!!substr(cats(put(md5(name),$hex32.)),1,27); + + call symputx(cats('name',_n_),name,'l'); + call symputx(cats('newname',_n_),newname,'l'); + call symputx(cats('len',_n_),newlen,'l'); + call symputx(cats('fmt',_n_),fmt,'l'); + call symputx(cats('type',_n_),type,'l'); + if last then call symputx('nobs',_n_,'l'); +run; + +/* clean up */ +proc sql; +drop table &syslast; + +%if &nobs=0 %then %do; + %put Dataset &libds has no columns! + data &outds; + set &libds; + run; + %return; +%end; + +data &outds; + /* rename on entry */ + set &libds(rename=( +%local i; +%do i=1 %to &nobs; + &&name&i=&&newname&i +%end; + )); +%do i=1 %to &nobs; + length &&name&i $&&len&i; + &&name&i=left(put(&&newname&i,&&fmt&i)); + drop &&newname&i; +%end; + if _error_ then call symputx('syscc',1012); +run; + +%mend mp_ds2fmtds; \ No newline at end of file diff --git a/tests/base/mp_ds2fmtds.test.sas b/tests/base/mp_ds2fmtds.test.sas new file mode 100644 index 0000000..0d6de69 --- /dev/null +++ b/tests/base/mp_ds2fmtds.test.sas @@ -0,0 +1,28 @@ +/** + @file + @brief Testing mp_ds2fmtds.sas macro + +

SAS Macros

+ @li mp_ds2fmtds.sas + @li mp_assert.sas + +**/ + +proc sql; +create table test as select * from dictionary.tables where libname='SASHELP'; + +filename inc temp; +data _null_; + set work.test; + file inc; + line=cats('%mp_ds2fmtds(sashelp.',memname,',',memname,')'); + put line; +run; + +%inc inc; + +%mp_assert( + iftrue=(&syscc=0), + desc=Checking tables were created successfully, + outds=work.test_results +) \ No newline at end of file