<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Mostlyunoriginal&#039;s Blog</title>
	<atom:link href="http://mostlyunoriginal.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://mostlyunoriginal.wordpress.com</link>
	<description>For the proliferation of useful SAS knowledge</description>
	<lastBuildDate>Mon, 30 Nov 2009 03:12:22 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='mostlyunoriginal.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://1.gravatar.com/blavatar/10f59e3796dd4b0040dd104f2b841175?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>Mostlyunoriginal&#039;s Blog</title>
		<link>http://mostlyunoriginal.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://mostlyunoriginal.wordpress.com/osd.xml" title="Mostlyunoriginal&#039;s Blog" />
	<atom:link rel='hub' href='http://mostlyunoriginal.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Avoid Overlordish Setting of Options in Your Shared Programs</title>
		<link>http://mostlyunoriginal.wordpress.com/2009/11/24/avoid-overlordish-setting-of-options-in-your-shared-programs/</link>
		<comments>http://mostlyunoriginal.wordpress.com/2009/11/24/avoid-overlordish-setting-of-options-in-your-shared-programs/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 20:41:57 +0000</pubDate>
		<dc:creator>mostlyunoriginal</dc:creator>
				<category><![CDATA[SAS]]></category>
		<category><![CDATA[options]]></category>
		<category><![CDATA[proc optload]]></category>
		<category><![CDATA[proc optsave]]></category>

		<guid isPermaLink="false">http://mostlyunoriginal.wordpress.com/?p=39</guid>
		<description><![CDATA[Use two simple Procs to make your shared programs run with the options profile you want without interfering with users' preset system options.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mostlyunoriginal.wordpress.com&amp;blog=10610850&amp;post=39&amp;subd=mostlyunoriginal&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I used to go one of two routes when writing programs: (1) Include an options statement in the program to make it run how I want (2) Leave out the options statement and let the performance of the program be determined by the user&#8217;s preset system options.  Often (2) occurs because I have written a program for myself, and I know what my default options will be.  But, often, I share programs that were originally only intended for my own use.</p>
<p>Typically (1) is not <em>necessary</em>, but performance and/or output may not be optimized if certain options are not set properly.  For instance, if I&#8217;ve got a program that creates ~20k local macro variables as part of its processing, it&#8217;s probably best that <a href="http://support.sas.com/onlinedoc/913/getDoc/en/mcrolref.hlp/a000543586.htm">SYMBOLGEN</a> is not turned on when it&#8217;s executed.  So, what to do?  Well, by using <a href="http://support.sas.com/onlinedoc/913/getDoc/en/proc.hlp/a002214507.htm">PROC OPTSAVE</a> and <a href="http://support.sas.com/onlinedoc/913/getDoc/en/proc.hlp/a002214501.htm">PROC OPTLOAD</a>, you can allow your programs to run the way you want, without overwriting users&#8217; options.</p>
<p>At the beginning of your program, before the options statement, insert the following:</p>
<pre>proc optsave out=<em>libref.dataset</em>;
</pre>
<p>You don&#8217;t have to specify the &#8216;out=&#8217; option &#8211; the default is SASUSER.MYOPTS, or WORK.MYOPTS if SASUSER is unavailable.  I prefer to specify the location myself with a data set name that won&#8217;t likely interfere with anything the user would not want overwritten &#8211; something like WORK.&lt;<em>program name</em>&gt;_OPTSET.  Then, simply set the options that are appropriate for the program.  At the end of the program, insert the following:</p>
<pre>proc optload data=<em>libref.dataset</em>;
</pre>
<p>This will restore the user&#8217;s options to those which were in place before the program was run.  Voila! Now your program will run at its best without mucking about with anyone&#8217;s preferred options.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mostlyunoriginal.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mostlyunoriginal.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mostlyunoriginal.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mostlyunoriginal.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mostlyunoriginal.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mostlyunoriginal.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mostlyunoriginal.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mostlyunoriginal.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mostlyunoriginal.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mostlyunoriginal.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mostlyunoriginal.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mostlyunoriginal.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mostlyunoriginal.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mostlyunoriginal.wordpress.com/39/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mostlyunoriginal.wordpress.com&amp;blog=10610850&amp;post=39&amp;subd=mostlyunoriginal&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mostlyunoriginal.wordpress.com/2009/11/24/avoid-overlordish-setting-of-options-in-your-shared-programs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/bf1389ab330a9e7fa3500cdab9b1b4e2?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mostlyunoriginal</media:title>
		</media:content>
	</item>
		<item>
		<title>%SYSFUNC Changed My Life</title>
		<link>http://mostlyunoriginal.wordpress.com/2009/11/22/sysfunc-changed-my-life/</link>
		<comments>http://mostlyunoriginal.wordpress.com/2009/11/22/sysfunc-changed-my-life/#comments</comments>
		<pubDate>Sun, 22 Nov 2009 02:11:09 +0000</pubDate>
		<dc:creator>mostlyunoriginal</dc:creator>
				<category><![CDATA[SAS]]></category>
		<category><![CDATA[%dswhere]]></category>
		<category><![CDATA[%wordcount]]></category>
		<category><![CDATA[attrn function]]></category>
		<category><![CDATA[close function]]></category>
		<category><![CDATA[command macro]]></category>
		<category><![CDATA[data step]]></category>
		<category><![CDATA[macro]]></category>
		<category><![CDATA[macro facility]]></category>
		<category><![CDATA[macro language]]></category>
		<category><![CDATA[open function]]></category>
		<category><![CDATA[statistical programming]]></category>
		<category><![CDATA[sysfunc]]></category>

		<guid isPermaLink="false">http://mostlyunoriginal.wordpress.com/?p=4</guid>
		<description><![CDATA[The advanced SAS user can use %SYSFUNC to harness the functionality of the Data Step with the contextual flexibility of the Macro facility to create some very useful and powerful utilities.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mostlyunoriginal.wordpress.com&amp;blog=10610850&amp;post=4&amp;subd=mostlyunoriginal&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Well, my life as a statistical programmer, anyway.</p>
<p>For those who deal heavily with the often cumbersome issues of data management, the SAS Macro facility can be an indispensable tool.  I most often find that macro code is used to automate repetitive tasks and to generalize programs across various parameters &#8211; these are, of course, very valuable capabilities.  But, aside from these more common uses, I have found great value in using the macro language (with a healthy smattering of %SYSFUNC) to construct stand-alone utilities to be used in a variety of contexts.</p>
<p>So, what is %SYSFUNC?  Well, as always, I would direct the curious SAS programmer to have a gander at the <a href="http://support.sas.com/onlinedoc/913/getDoc/en/mcrolref.hlp/z3514sysfunc.htm">online doc</a>, but for simplicity I&#8217;ll just say that it&#8217;s a macro function that allows the use of Base SAS functions, outside of the Data Step &#8211; a sort of SAS Rosetta Stone, if you will.  So, why is that useful?  Let&#8217;s look at a simple example.</p>
<p>Suppose you need your program to iterate some steps over an unknown number of variables in a user-supplied variable list &#8211; how would you do that?  Well, as with most programming challenges, I&#8217;m quite certain there are many ways &#8211; one way is to use the simple macro function, %WORDCOUNT:</p>
<pre>%macro wordcount(varlist, delim=' ');
  %let count=%eval(%sysfunc(countc(%qsysfunc(compbl(&amp;varlist)), &amp;delim)) + 1);
  &amp;count
%mend wordcount;</pre>
<p>%WORDCOUNT takes as arguments a variable list and the associated delimiter (defaulting to space-delimited).  Then, by using the <a href="http://support.sas.com/onlinedoc/913/getDoc/en/lrdict.hlp/a002260840.htm">COUNTC</a> function (this is a Base SAS function, and there is no macro equivalent) nested within %SYSFUNC, it counts the number of delimiters, adds one and saves the result to the macro variable <em>&amp;count</em>.  <a href="http://support.sas.com/onlinedoc/913/getDoc/en/lrdict.hlp/a000214211.htm">COMPBL</a> (nested within %QSYSFUNC &#8211; see the section below discussing comma-delimited variable lists) is used to collapse multiple blanks into a single blank space &#8211; this prevents COUNTC from overcounting when multiple spaces occur between variables in a space-delimited list.  Note on the third line of the program that <em>&amp;count</em> appears without a semicolon, this makes %WORDCOUNT an in-line function.  Let&#8217;s see an example of how %WORDCOUNT could work inside of a macro program.</p>
<pre>%macro example;
  %let varlist= one two three four;
  %do i=1 %to %wordcount(&amp;varlist);
    %let varname=%scan(&amp;varlist, &amp;i);
    %put  current variable name is &amp;varname;
  %end;
%mend;</pre>
<p>Upon execution of the above example program, the following is printed to the log:</p>
<pre>current variable name is one
current variable name is two
current variable name is three
current variable name is four</pre>
<p>Alternative delimiters may be used in %WORDCOUNT as well.  If the variable is comma-delimited, the macro should be called as follows:</p>
<pre>%wordcount(%quote(&amp;varlist), delim=%str(,))</pre>
<p>Here, to keep SAS from becoming confused into thinking we are attempting to supply too many parameters, %QUOTE masks the commas in <em>&amp;varlist</em> at execution time, and %STR masks the comma supplied as the delimiter parameter at compilation time.  %QUOTE masks the commas in <em>&amp;varlist</em> only until it is passed to COMPBBL (%SYSFUNC will return an unquoted result, even if a macro quoting function has previously been used &#8211; %QSYSFUNC returns a quoted result).  By nesting COMPBL in %QSYSFUNC, the commas in <em>&amp;varlist</em> are re-masked before the string is passed to COUNTC.</p>
<p>Okay, so that could be useful , but it&#8217;s not exactly mind-blowing.  Let&#8217;s consider a more complex example.  Think of the ways that you would find the number of observations in a data set.  Now, what if you want to find the number of observations satisfying a certain set of conditions?   The %DSWHERE macro takes as arguments a data set name and a where clause (which defaults to true &#8211; if the user simply wants the total number of observations), saves the resulting count in a global macro variable and prints the results to the log.</p>
<pre>%macro dswhere(dataset, where=1) /cmd;                        /* 1 */
  %let ds=&amp;dataset.(where=(&amp;where));
  %let dsid=%sysfunc(open(&amp;ds));                              /* 2 */
  %if &amp;dsid=^0 %then %do;                                     /* 3 */
    %global number;
    %if &amp;where=1 %then %do;
      %let number=%sysfunc(attrn(&amp;dsid,nlobs));               /* 4 */
      %put &amp;number OBSERVATIONS IN &amp;dataset;
    %end;
    %else %do;
      %let number=%sysfunc(attrn(&amp;dsid,nlobsf));              /* 5 */
      %put &amp;number OBSERVATIONS IN &amp;dataset WHERE &amp;where;
    %end;
  %end;
  %else %do;
    %put %sysfunc(sysmsg());
  %end;
  %let dsid=%sysfunc(close(&amp;dsid));                           /* 6 */
  %if &amp;dsid=^0 %then %do;                                     /* 7 */
    %put THE DATASET: &amp;dataset WAS NOT CLOSED;
  %end;
%mend dswhere;</pre>
<p>Okay, there&#8217;s quite a lot going on here&#8230;</p>
<p>(1) Note the <a href="http://support.sas.com/onlinedoc/913/getDoc/en/mcrolref.hlp/macro-stmt.htm">&#8216;cmd&#8217;</a> option in the %MACRO statement.  If the <a href="http://support.sas.com/onlinedoc/913/getDoc/en/mcrolref.hlp/a000543685.htm">&#8216;cmdmac&#8217;</a> system option is turned on (a good option to include in your autoexec file), and the &#8216;cmd&#8217; option is included in the definition of a macro that contains only macro code and/or command statements, the macro may be called from the command line in standard command syntax (no percent symbol, parentheses or commas to separate parameters).  Command syntax and the aforementioned options aren&#8217;t required to call a macro from the command line &#8211; any macro containing only macro code and/or command statements may be called from the command line in normal macro syntax.</p>
<p>(2) This is a biggie &#8211; the <a href="http://support.sas.com/onlinedoc/913/getDoc/en/lrdict.hlp/a000148395.htm">OPEN</a> function is arguably <em>the</em> function that makes %SYSFUNC so powerful.  So, what&#8217;s the big deal?  Well, the depth and breadth of what can be achieved by the pairing of %SYSFUNC and the OPEN function cannot be addressed in a single post, but for now we&#8217;ll focus on the ability to use this combination to access metadata for our SAS data sets.</p>
<p>(3) If the data set has been successfully opened, the return code, saved in <em>&amp;dsid</em>, will be a unique data set identifier.  If not, <em>&amp;dsid</em>=0;</p>
<p>(4) Once a data set is open, the <a href="http://support.sas.com/onlinedoc/913/getDoc/en/lrdict.hlp/a000212040.htm">ATTRN</a> function may be used to obtain certain numeric attributes associated with it (the <a href="http://support.sas.com/onlinedoc/913/getDoc/en/lrdict.hlp/a000147794.htm">ATTRC</a> function may be similarly used for character attributes); in this case the &#8216;nlobs&#8217; parameter indicates that the attribute to be returned is the number of logical observations in the data set.</p>
<p>(5) If the user has supplied a where clause, the &#8216;nlobsf&#8217; parameter is fed into the ATTRN function to indicate that we wish to return the number of observations satisfying an active where clause (the data set will have been opened with the user-supplied where clause in place).  We could discard the condition on whether or not the user supplied a where clause and simply always use &#8216;nlobsf&#8217;, but it causes ATTRN to be less efficient &#8211; better to only use it if we have to.</p>
<p>(6) The <a href="http://support.sas.com/onlinedoc/913/getDoc/en/lrdict.hlp/a000212086.htm">CLOSE</a> function is used to, well, close the data set once we are done with it (this is important &#8211; don&#8217;t forget to close your data sets!).</p>
<p>(7) CLOSE returns 0 if the action was successful.</p>
<p>Now, let&#8217;s have an example of this puppy in action, shall we?</p>
<pre>/* Create a testing data set with the variable <em>var</em> that randomly takes values of A or B */

data testing;
  do i=1 to 1000;
    if ranuni(-1) le .5 then var='A';
    else var='B';
    output;
  end;
run;

/* Call %dswhere without a where clause */

%dswhere(testing)

/* Call %dswhere with a where clause */

%dswhere(testing, where= var='A')</pre>
<p>Upon execution of the above macro calls, the following is printed to the log:</p>
<pre>1000 OBSERVATIONS IN testing
511 OBSERVATIONS IN testing WHERE var='A'</pre>
<p>Note also that following execution of %DSWHERE the global macro variable <em>&amp;number</em> will contain the result.  So, %DSWHERE can be used within a program to pass its result for further processing or from the command line as part of ad-hoc review.  I have %DSWHERE included in my macro autocall library (a subsequent post) so it is always available for command line use.</p>
<p>So, %SYSFUNC has allowed me to create a handy word-counting macro function and an observation-counting command/utility macro with subsetting capabilities that can be either embedded in a program or used interactively.  There is <em>a lot</em> more that can be achieved through the use of %SYSFUNC &#8211; I&#8217;m always finding new ways to use it, and I&#8217;m sure that many of them will be covered in subsequent posts.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mostlyunoriginal.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mostlyunoriginal.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mostlyunoriginal.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mostlyunoriginal.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mostlyunoriginal.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mostlyunoriginal.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mostlyunoriginal.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mostlyunoriginal.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mostlyunoriginal.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mostlyunoriginal.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mostlyunoriginal.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mostlyunoriginal.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mostlyunoriginal.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mostlyunoriginal.wordpress.com/4/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mostlyunoriginal.wordpress.com&amp;blog=10610850&amp;post=4&amp;subd=mostlyunoriginal&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mostlyunoriginal.wordpress.com/2009/11/22/sysfunc-changed-my-life/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/bf1389ab330a9e7fa3500cdab9b1b4e2?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mostlyunoriginal</media:title>
		</media:content>
	</item>
	</channel>
</rss>
