From e0469be0d8f15a9a74b0894ee1e7e890de09bff1 Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Tue, 3 May 2022 15:24:22 +0000 Subject: [PATCH 1/3] feat: updating mf_getvarcount to allow filtering by column type --- base/mf_getuniquelibref.sas | 10 ++--- base/mf_getvarcount.sas | 27 +++++++++++--- tests/crossplatform/mf_getvarcount.test.sas | 41 +++++++++++++++++++++ 3 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 tests/crossplatform/mf_getvarcount.test.sas diff --git a/base/mf_getuniquelibref.sas b/base/mf_getuniquelibref.sas index c5eb387..b9d7efc 100644 --- a/base/mf_getuniquelibref.sas +++ b/base/mf_getuniquelibref.sas @@ -3,12 +3,12 @@ @brief Returns an unused libref @details Use as follows: - libname mclib0 (work); - libname mclib1 (work); - libname mclib2 (work); + libname mclib0 (work); + libname mclib1 (work); + libname mclib2 (work); - %let libref=%mf_getuniquelibref(); - %put &=libref; + %let libref=%mf_getuniquelibref(); + %put &=libref; which returns: diff --git a/base/mf_getvarcount.sas b/base/mf_getvarcount.sas index e2861ca..8687caf 100644 --- a/base/mf_getvarcount.sas +++ b/base/mf_getvarcount.sas @@ -2,31 +2,48 @@ @file @brief Returns number of variables in a dataset @details Useful to identify those renagade datasets that have no columns! + Can also be used to count for numeric, or character columns - %put Number of Variables=%mf_getvarcount(sashelp.class); + %put Number of Variables=%mf_getvarcount(sashelp.class); + %put Character Variables=%mf_getvarcount(sashelp.class,typefilter=C); + %put Numeric Variables = %mf_getvarcount(sashelp.class,typefilter=N); returns: > Number of Variables=4 - @param libds Two part dataset (or view) reference. + + @param [in] libds Two part dataset (or view) reference. + @param [in] typefilter= (A) Filter for certain types of column. Valid values: + @li A Count All columns + @li C Count Character columns only + @li N Count Numeric columns only @version 9.2 @author Allan Bowe **/ -%macro mf_getvarcount(libds +%macro mf_getvarcount(libds,typefilter=A )/*/STORE SOURCE*/; - %local dsid nvars rc ; + %local dsid nvars rc outcnt x; %let dsid=%sysfunc(open(&libds)); %let nvars=.; + %let outcnt=0; + %let typefilter=%upcase(&typefilter); %if &dsid %then %do; %let nvars=%sysfunc(attrn(&dsid,NVARS)); + %if &typefilter=A %then %let outcnt=&nvars; + %else %if &nvars>0 %then %do x=1 %to &nvars; + /* increment based on variable type */ + %if %sysfunc(vartype(&dsid,&x))=&typefilter %then %do; + %let outcnt=%eval(&outcnt+1); + %end; + %end; %let rc=%sysfunc(close(&dsid)); %end; %else %do; %put unable to open &libds (rc=&dsid); %let rc=%sysfunc(close(&dsid)); %end; - &nvars + &outcnt %mend mf_getvarcount; \ No newline at end of file diff --git a/tests/crossplatform/mf_getvarcount.test.sas b/tests/crossplatform/mf_getvarcount.test.sas new file mode 100644 index 0000000..bdf23b9 --- /dev/null +++ b/tests/crossplatform/mf_getvarcount.test.sas @@ -0,0 +1,41 @@ +/** + @file + @brief Testing mf_getvarlist macro + +

SAS Macros

+ @li mf_getvarcount.sas + +**/ + +data work.all work.nums(keep=num1 num2) work.chars(keep=char1 char2); + length num1 num2 8 char1 char2 char3 $4; + call missing (of _all_); + output; +run; + +%mp_assert( + iftrue=(%mf_getvarcount(work.all)=5), + desc=%str(Checking for mixed vars), + outds=work.test_results +) +%mp_assert( + iftrue=(%mf_getvarcount(work.all,typefilter=C)=3), + desc=%str(Checking for char in mixed vars), + outds=work.test_results +) +%mp_assert( + iftrue=(%mf_getvarcount(work.all,typefilter=N)=2), + desc=%str(Checking for num in mixed vars), + outds=work.test_results +) +%mp_assert( + iftrue=(%mf_getvarcount(work.nums,typefilter=c)=0), + desc=%str(Checking for char in num vars), + outds=work.test_results +) +%mp_assert( + iftrue=(%mf_getvarcount(work.chars,typefilter=N)=0), + desc=%str(Checking for num in char vars), + outds=work.test_results +) + From 4a8f7bb0142a9bce1772881dc118996815e59dd4 Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Tue, 3 May 2022 15:46:15 +0000 Subject: [PATCH 2/3] fix: all the fixings --- base/mp_abort.sas | 7 +++- base/mp_getmaxvarlengths.sas | 30 ++++++++++++-- base/mp_storediffs.sas | 6 +-- tests/crossplatform/mf_getvarcount.test.sas | 5 +++ .../mp_getmaxvarlengths.test.sas | 40 ++++++++++++++++++- 5 files changed, 80 insertions(+), 8 deletions(-) diff --git a/base/mp_abort.sas b/base/mp_abort.sas index ff8926d..039272a 100644 --- a/base/mp_abort.sas +++ b/base/mp_abort.sas @@ -89,7 +89,12 @@ or "&SYSPROCESSNAME "="Compute Server " or &mode=INCLUDE %then %do; - options obs=max replace nosyntaxcheck mprint; + options obs=max replace mprint; + %if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" + %then %do; + options nosyntaxcheck; + %end; + %if &mode=INCLUDE %then %do; %if %sysfunc(exist(&errds))=1 %then %do; data _null_; diff --git a/base/mp_getmaxvarlengths.sas b/base/mp_getmaxvarlengths.sas index 133f249..92d422f 100755 --- a/base/mp_getmaxvarlengths.sas +++ b/base/mp_getmaxvarlengths.sas @@ -41,6 +41,7 @@

SAS Macros

@li mcf_length.sas @li mf_getuniquename.sas + @li mf_getvarcount.sas @li mf_getvarlist.sas @li mf_getvartype.sas @li mf_getvarformat.sas @@ -60,7 +61,7 @@ ,outds=work.mp_getmaxvarlengths )/*/STORE SOURCE*/; -%local vars prefix x var fmt; +%local vars prefix x var fmt srcds; %let vars=%mf_getvarlist(libds=&libds); %let prefix=%substr(%mf_getuniquename(),1,25); %let num2char=%upcase(&num2char); @@ -70,6 +71,24 @@ %mcf_length(wrap=YES, insert_cmplib=YES) %end; +%if &num2char=NO + and ("%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5") + and %mf_getvarcount(&libds,typefilter=N) gt 0 +%then %do; + /* custom functions not supported in summary operations */ + %let srcds=%mf_getuniquename(); + data &srcds/view=&srcds; + set &libds; + %do x=1 %to %sysfunc(countw(&vars,%str( ))); + %let var=%scan(&vars,&x); + %if %mf_getvartype(&libds,&var)=N %then %do; + &prefix.&x=mcf_length(&var); + %end; + %end; + run; +%end; +%else %let srcds=&libds; + proc sql; create table &outds (rename=( %do x=1 %to %sysfunc(countw(&vars,%str( ))); @@ -94,10 +113,15 @@ create table &outds (rename=( %end; %end; %else %do; - max(mcf_length(&var)) as &prefix.&x + %if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do; + max(&prefix.&x) as &prefix.&x + %end; + %else %do; + max(mcf_length(&var)) as &prefix.&x + %end; %end; %end; - from &libds; + from &srcds; proc transpose data=&outds out=&outds(rename=(_name_=NAME COL1=MAXLEN)); diff --git a/base/mp_storediffs.sas b/base/mp_storediffs.sas index 878cb55..96b645f 100644 --- a/base/mp_storediffs.sas +++ b/base/mp_storediffs.sas @@ -125,7 +125,7 @@ data &ds1; set &dslist indsname=&inds_auto; &hashkey=put(md5(catx('|',%mf_getquotedstr(&key,quote=N))),$hex32.); - &inds_keep=&inds_auto; + &inds_keep=upcase(&inds_auto); proc sort; by &inds_keep &hashkey; run; @@ -160,8 +160,8 @@ data &ds4; tgtvar_nm=upcase(tgtvar_nm); if tgtvar_nm in (%upcase(&vlist)); - if &inds_auto="&ds2" then tgtvar_type='N'; - else if &inds_auto="&ds3" then tgtvar_type='C'; + if upcase(&inds_auto)="&ds2" then tgtvar_type='N'; + else if upcase(&inds_auto)="&ds3" then tgtvar_type='C'; else do; putlog "%str(ERR)OR: unidentified vartype input!" &inds_auto; call symputx('syscc',98); diff --git a/tests/crossplatform/mf_getvarcount.test.sas b/tests/crossplatform/mf_getvarcount.test.sas index bdf23b9..dabe961 100644 --- a/tests/crossplatform/mf_getvarcount.test.sas +++ b/tests/crossplatform/mf_getvarcount.test.sas @@ -4,6 +4,7 @@

SAS Macros

@li mf_getvarcount.sas + @li mp_assertscope.sas **/ @@ -13,6 +14,10 @@ data work.all work.nums(keep=num1 num2) work.chars(keep=char1 char2); output; run; +%mp_assertscope(SNAPSHOT) +%put scope check:%mf_getvarcount(work.all); +%mp_assertscope(COMPARE) + %mp_assert( iftrue=(%mf_getvarcount(work.all)=5), desc=%str(Checking for mixed vars), diff --git a/tests/crossplatform/mp_getmaxvarlengths.test.sas b/tests/crossplatform/mp_getmaxvarlengths.test.sas index 2ec974f..baf1e6e 100644 --- a/tests/crossplatform/mp_getmaxvarlengths.test.sas +++ b/tests/crossplatform/mp_getmaxvarlengths.test.sas @@ -10,10 +10,48 @@ **/ +data work.class ; +attrib +Name length= $8 +Sex length= $1 +Age length= 8 +Height length= 8 +Weight length= 8 +; +infile cards dsd; +input + Name :$char. + Sex :$char. + Age + Height + Weight +; +datalines4; +Alfred,M,14,69,112.5 +Alice,F,13,56.5,84 +Barbara,F,13,65.3,98 +Carol,F,14,62.8,102.5 +Henry,M,14,63.5,102.5 +James,M,12,57.3,83 +Jane,F,12,59.8,84.5 +Janet,F,15,62.5,112.5 +Jeffrey,M,13,62.5,84 +John,M,12,59,99.5 +Joyce,F,11,51.3,50.5 +Judy,F,14,64.3,90 +Louise,F,12,56.3,77 +Mary,F,15,66.5,112 +Philip,M,16,72,150 +Robert,M,12,64.8,128 +Ronald,M,15,67,133 +Thomas,M,11,57.5,85 +William,M,15,66.5,112 +;;;; +run; /* regular usage */ %mp_assertscope(SNAPSHOT) -%mp_getmaxvarlengths(sashelp.class,outds=work.myds) +%mp_getmaxvarlengths(work.class,outds=work.myds) %mp_assertscope(COMPARE,desc=checking scope leakage on mp_getmaxvarlengths) %mp_assert( iftrue=(&syscc=0), From fc9b7652462b9dda244ee465857f28338fad84d3 Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Tue, 3 May 2022 15:46:34 +0000 Subject: [PATCH 3/3] chore: updating all.sas --- all.sas | 80 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/all.sas b/all.sas index 93df8ed..e8a1427 100644 --- a/all.sas +++ b/all.sas @@ -994,12 +994,12 @@ or %index(&pgm,/tests/testteardown) @brief Returns an unused libref @details Use as follows: - libname mclib0 (work); - libname mclib1 (work); - libname mclib2 (work); + libname mclib0 (work); + libname mclib1 (work); + libname mclib2 (work); - %let libref=%mf_getuniquelibref(); - %put &=libref; + %let libref=%mf_getuniquelibref(); + %put &=libref; which returns: @@ -1148,33 +1148,50 @@ or %index(&pgm,/tests/testteardown) @file @brief Returns number of variables in a dataset @details Useful to identify those renagade datasets that have no columns! + Can also be used to count for numeric, or character columns - %put Number of Variables=%mf_getvarcount(sashelp.class); + %put Number of Variables=%mf_getvarcount(sashelp.class); + %put Character Variables=%mf_getvarcount(sashelp.class,typefilter=C); + %put Numeric Variables = %mf_getvarcount(sashelp.class,typefilter=N); returns: > Number of Variables=4 - @param libds Two part dataset (or view) reference. + + @param [in] libds Two part dataset (or view) reference. + @param [in] typefilter= (A) Filter for certain types of column. Valid values: + @li A Count All columns + @li C Count Character columns only + @li N Count Numeric columns only @version 9.2 @author Allan Bowe **/ -%macro mf_getvarcount(libds +%macro mf_getvarcount(libds,typefilter=A )/*/STORE SOURCE*/; - %local dsid nvars rc ; + %local dsid nvars rc outcnt x; %let dsid=%sysfunc(open(&libds)); %let nvars=.; + %let outcnt=0; + %let typefilter=%upcase(&typefilter); %if &dsid %then %do; %let nvars=%sysfunc(attrn(&dsid,NVARS)); + %if &typefilter=A %then %let outcnt=&nvars; + %else %if &nvars>0 %then %do x=1 %to &nvars; + /* increment based on variable type */ + %if %sysfunc(vartype(&dsid,&x))=&typefilter %then %do; + %let outcnt=%eval(&outcnt+1); + %end; + %end; %let rc=%sysfunc(close(&dsid)); %end; %else %do; %put unable to open &libds (rc=&dsid); %let rc=%sysfunc(close(&dsid)); %end; - &nvars + &outcnt %mend mf_getvarcount;/** @file @brief Returns the format of a variable @@ -2203,7 +2220,12 @@ Usage: or "&SYSPROCESSNAME "="Compute Server " or &mode=INCLUDE %then %do; - options obs=max replace nosyntaxcheck mprint; + options obs=max replace mprint; + %if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" + %then %do; + options nosyntaxcheck; + %end; + %if &mode=INCLUDE %then %do; %if %sysfunc(exist(&errds))=1 %then %do; data _null_; @@ -7458,6 +7480,7 @@ create table &outsummary as

SAS Macros

@li mcf_length.sas @li mf_getuniquename.sas + @li mf_getvarcount.sas @li mf_getvarlist.sas @li mf_getvartype.sas @li mf_getvarformat.sas @@ -7477,7 +7500,7 @@ create table &outsummary as ,outds=work.mp_getmaxvarlengths )/*/STORE SOURCE*/; -%local vars prefix x var fmt; +%local vars prefix x var fmt srcds; %let vars=%mf_getvarlist(libds=&libds); %let prefix=%substr(%mf_getuniquename(),1,25); %let num2char=%upcase(&num2char); @@ -7487,6 +7510,24 @@ create table &outsummary as %mcf_length(wrap=YES, insert_cmplib=YES) %end; +%if &num2char=NO + and ("%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5") + and %mf_getvarcount(&libds,typefilter=N) gt 0 +%then %do; + /* custom functions not supported in summary operations */ + %let srcds=%mf_getuniquename(); + data &srcds/view=&srcds; + set &libds; + %do x=1 %to %sysfunc(countw(&vars,%str( ))); + %let var=%scan(&vars,&x); + %if %mf_getvartype(&libds,&var)=N %then %do; + &prefix.&x=mcf_length(&var); + %end; + %end; + run; +%end; +%else %let srcds=&libds; + proc sql; create table &outds (rename=( %do x=1 %to %sysfunc(countw(&vars,%str( ))); @@ -7511,10 +7552,15 @@ create table &outds (rename=( %end; %end; %else %do; - max(mcf_length(&var)) as &prefix.&x + %if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do; + max(&prefix.&x) as &prefix.&x + %end; + %else %do; + max(mcf_length(&var)) as &prefix.&x + %end; %end; %end; - from &libds; + from &srcds; proc transpose data=&outds out=&outds(rename=(_name_=NAME COL1=MAXLEN)); @@ -11546,7 +11592,7 @@ select distinct tgtvar_nm into: missvars separated by ' ' data &ds1; set &dslist indsname=&inds_auto; &hashkey=put(md5(catx('|',%mf_getquotedstr(&key,quote=N))),$hex32.); - &inds_keep=&inds_auto; + &inds_keep=upcase(&inds_auto); proc sort; by &inds_keep &hashkey; run; @@ -11581,8 +11627,8 @@ data &ds4; tgtvar_nm=upcase(tgtvar_nm); if tgtvar_nm in (%upcase(&vlist)); - if &inds_auto="&ds2" then tgtvar_type='N'; - else if &inds_auto="&ds3" then tgtvar_type='C'; + if upcase(&inds_auto)="&ds2" then tgtvar_type='N'; + else if upcase(&inds_auto)="&ds3" then tgtvar_type='C'; else do; putlog "%str(ERR)OR: unidentified vartype input!" &inds_auto; call symputx('syscc',98);