diff --git a/base/mf_getvalue.sas b/base/mf_getvalue.sas index 63bfb34..af56b5b 100644 --- a/base/mf_getvalue.sas +++ b/base/mf_getvalue.sas @@ -1,7 +1,8 @@ /** @file - @brief Retrieves a value from a dataset. If no filter supplied, then first - record is used. + @brief Retrieves a value from a dataset. Returned value is fetched from the + 'fetchobs=' record (row 1 by default), after applying the optional filter. + @details Be sure to %quote() your where clause. Example usage: %put %mf_getvalue(sashelp.class,name,filter=%quote(age=15)); @@ -16,21 +17,39 @@ @param [in] libds dataset to query @param [in] variable the variable which contains the value to return. @param [in] filter= (1) contents of where clause + @param [in] fetchobs= (1) observation to fetch. NB: Filter applies first. @version 9.2 @author Allan Bowe **/ -%macro mf_getvalue(libds,variable,filter=1 +%macro mf_getvalue(libds,variable,filter=1,fetchobs=1 )/*/STORE SOURCE*/; - %if %mf_getattrn(&libds,NLOBS)>0 %then %do; - %local dsid rc &variable; - %let dsid=%sysfunc(open(&libds(where=(&filter)))); + %local dsid; + + %let dsid=%sysfunc(open(&libds(where=(&filter)))); + %if (&dsid) %then %do; + %local rc &variable; %syscall set(dsid); - %let rc = %sysfunc(fetch(&dsid)); + %let rc = %sysfunc(fetchobs(&dsid,&fetchobs)); + %if (&rc ne 0) %then %do; + %put NOTE: Problem reading obs &fetchobs from &libds..; + %put %sysfunc(sysmsg()); + /* Coerce an rc value of -1 (read past end of data) to a 4 + that, in SAS condition code terms, represents the sysmsg + w@rning it generates. */ + %if &rc eq -1 %then %let rc = 4; + /* And update SYSCC if the &rc value is higher */ + %let syscc = %sysfunc(max(&syscc,&rc)); + %end; %let rc = %sysfunc(close(&dsid)); %trim(&&&variable) %end; -%mend mf_getvalue; \ No newline at end of file + %else %do; + %put %sysfunc(sysmsg()); + %let syscc = %sysfunc(max(&syscc,%sysfunc(sysrc()))); + %end; + +%mend mf_getvalue; diff --git a/tests/base/mf_getvalue.test.sas b/tests/base/mf_getvalue.test.sas new file mode 100644 index 0000000..15d45f5 --- /dev/null +++ b/tests/base/mf_getvalue.test.sas @@ -0,0 +1,91 @@ +/** + @file + @brief Testing mf_getvalue macro + +

SAS Macros

+ @li mf_getvalue.sas + @li mp_assert.sas + @li mp_assertscope.sas + +**/ + +data work.test_data; + do i = 1 to 10; + output; + end; + stop; +run; + +/* - Test 1 - + Get value from default first observation. + No filter. +*/ +%mp_assertscope(SNAPSHOT) +%let test_value=%mf_getvalue(work.test_data,i); +%mp_assertscope(COMPARE,ignorelist=test_value) + +%mp_assert( + iftrue=(&test_value=1 and &syscc eq 0), + desc=Basic test fetching value from default first obs, + outds=work.test_results +) + +/* - Test 2 - + Get value from 10th observation. + No filter. +*/ +%let test_value=%mf_getvalue(work.test_data,i,fetchobs=10); +%mp_assert( + iftrue=(&test_value=10 and &syscc eq 0), + desc=Test fetching value from specifically the 10th row, + outds=work.test_results +) + +/* - Test 3 - + Get value from default first observation. + With filter. +*/ +%let test_value=%mf_getvalue(work.test_data,i,filter=(i>4)); +%mp_assert( + iftrue=(&test_value=5 and &syscc eq 0), + desc=Test fetching value from default row of filtered data, + outds=work.test_results +) + +/* - Test 4 - + Get value from specified observation. + With filter. +*/ +%let test_value=%mf_getvalue(work.test_data,i,filter=(i>4),fetchobs=5); +%mp_assert( + iftrue=(&test_value=9 and &syscc eq 0), + desc=Test fetching value from 5th row of filtered data, + outds=work.test_results +) + +/* - Test 5 - + Get value from default observation. + Filter removes all rows. This simulates providing an empty dataset + or specifying an observation number beyond the set returned by the filter. +*/ +%let test_value=%mf_getvalue(work.test_data,i,filter=(i>10)); +%mp_assert( + iftrue=(&test_value=%str() and &syscc eq 4), + desc=Test fetching value from 1st row of empty (filtered) data, + outds=work.test_results +) + +%let syscc = 0; /* Reset w@rning To ensure confidence in next test */ + +/* - Test 6 - + Get value from default observation. + Dataset does not exist. +*/ +%let test_value=%mf_getvalue(work.test_data_x,i); +%mp_assert( + iftrue=(&test_value=%str() and &syscc gt 0), + desc=Test fetching value from 1st row of non-existent data, + outds=work.test_results +) + +%let syscc = 0; /* To reset expected error and allow test job to exit clean. */