User robert penridge - RunSubmit.com most recent 30 from http://www.runsubmit.com 2010-07-29T19:56:55Z http://www.runsubmit.com/feeds/user/66 http://www.creativecommons.org/licenses/by-nc/2.5/rdf http://www.runsubmit.com/questions/339/how-to-find-the-end-of-week-date-for-a-given-date/351#351 Answer by Robert Penridge for How to find the End of Week Date for a given date....? Robert Penridge 2010-07-29T14:49:35Z 2010-07-29T14:49:35Z <p>As Matt suggested (but didn't give an example of) I would just go with a simple call to the intnx() function without any macro wrapper.</p> <pre><code>data _null_; date = mdy(7,27,2010); end_of_week_date = intnx("week.1", date, 0, "end"); put end_of_week_date date9.; run; </code></pre> <p>Adding a macro wrapper to a simple function call adds unnecessary complexity and doesn't add any value. That is why the function already exists.</p> <p>Cheers Rob</p> http://www.runsubmit.com/questions/347/accessing-sas-dataset-through-odbc-sas-localprovider Accessing SAS Dataset through ODBC SAS.LocalProvider Robert Penridge 2010-07-29T00:37:12Z 2010-07-29T01:25:35Z <p>Hi All</p> <p>I'm trying to access a local SAS dataset from VBA in Excel 2007. Using code I found on the interwebs I can get it to return an entire table, but am not able to get it to execute an SQL statement. I did read on one messageboard that the LocalProvider does not accept SQL queries but was hoping someone may know otherwise or have an alternate technique. I don't have SAS/Share or SAS/IOM so those options are out.</p> <p>Note that in order to run the below test code you will need to add the following 3 references to your VBA Project via Tools->References 1) SASWorkSpaceManager 2) SAS: Integrated Object Model (IOM) 3) Microsoft ActiveX Data Objects</p> <pre><code>Public Sub GetData() ' DECLARE VARIABLES Dim obConnection As New ADODB.Connection Dim obRecordset As New ADODB.Recordset Dim i As Integer Dim strSQL As String obConnection.Provider = "sas.LocalProvider.9.2" obConnection.Properties("Data Source") = "C:\Program Files\SAS\SASFoundation\9.2\core\sashelp" obConnection.Open strSQL = "select * from class" 'METHOD 1 WORKS - BUT RETURNS ENTIRE DATASET obRecordset.Open "class", obConnection, adOpenStatic, adLockReadOnly, ADODB.adCmdTableDirect 'METHOD 2 DOESNT WORK 'obRecordset.Open "select name from class", obConnection, adOpenStatic, adLockReadOnly, ADODB.adCmdText ' ADD HEADER ROW Cells(1, 1).Select$ For i = 0 To obRecordset.Fields.Count - 1 ActiveCell.Offset(0, i).Value = obRecordset.Fields(i).Name Next i ' ADD DETAIL ROWS obRecordset.MoveFirst Cells(2, 1).Select ActiveCell.CopyFromRecordset obRecordset 'CLEANUP obRecordset.Close Set obRecordset = Nothing obConnection.Close Set obConnection = Nothing End Sub </code></pre> <p>For the record I have SAS 9.2 (TS Level 2M2), ADO 2.8, Excel 2007...</p> <p>Thanks Rob</p> <p>EDIT 1: I found this document which seems to imply that SQL queries are supported, as are inserts and updates (I only need to query though):</p> <p><a href="http://ftp.sas.com/techsup/download/v8papers/provider.pdf" rel="nofollow">ftp.sas.com/techsup/download/v8papers/provider.pdf</a></p> <p>EDIT 2: I found it does support the recordset filter property so I can at least filter the results like so:</p> <pre><code>obRecordset.Filter = "sex = 'M'" </code></pre> <p>It does not however use any indexes on the dataset =(</p> http://www.runsubmit.com/questions/330/mysql-odbc-returning-string-with-formathex14 MySQL ODBC returning string with format=$HEX14. Robert Penridge 2010-07-16T19:26:27Z 2010-07-23T17:01:45Z <p>Hi All</p> <p>The below passthrough query to a mySQL DB is for some reason assigning a HEX format to the second variable in the SAS dataset. I have just had to reinstall everything on my machine so I think this may be caused by a difference in ODBC driver version but am not sure. The issue is that I have 3 years worth of code that used to work just find but now it's displaying in hex. Any ideas to force it to use a $char format? Applying a cast statement to the code corrects the problem but I don't want to update 3 years worth of code!</p> <p>I've tried changing the charset in my ODBC configuration to UTF8 and LATIN1 but that didn't seem to make a difference. </p> <pre><code>proc sql; connect to odbc as conn (datasrc=analytics user=xxx password=xxx); create table x as select * from connection to conn ( select cast(substr(date_advance, 1,7) as char(7)) as good, /* FORMAT IN FINAL DS=$CHAR7. */ substr(date_advance, 1,7) as bad /* FORMAT IN FINAL DS=$HEX14. */ from analysis.loan ); disconnect from conn; quit; </code></pre> <p>Help! Rob</p> http://www.runsubmit.com/questions/332/sas-graph-educational-resources SAS/Graph Educational Resources Robert Penridge 2010-07-19T20:09:13Z 2010-07-22T16:50:44Z <p>Hi All</p> <p>Can anyone recommend a good SAS/Graph resource other than SAS OnlineDoc? I'm looking for something that starts with the very basics. </p> <p>EDIT: A good book would probably be best - I'd like to start simple but be able to work up to the more complex.</p> <p>Thanks Rob</p> http://www.runsubmit.com/questions/324/finding-similar-groups/328#328 Answer by Robert Penridge for Finding Similar Groups Robert Penridge 2010-07-15T16:27:39Z 2010-07-15T16:27:39Z <p>Perhaps you can do something like this:</p> <p>1) Sort by Group, Company</p> <p>2) Create a group signature by concatenating all groups for each company together into a single string. Be sure to also use a delimiter.</p> <p>3) Create a distinct list of the signatures and assign an ID to each.</p> <p>4) Match the ID back against the data from step 2.\</p> <pre><code>data x; attrib group format=best. company length=$1; input group $ company; datalines; 1 A 1 B 1 C 2 A 2 Z 3 A 3 B 3 C 4 B ; run; proc sort data=x; by group company; run; data x2; attrib sig length=$100; set x; by group; retain sig; if first.group then do; sig = company; end; else do; sig = catx('#',sig,company); end; if last.group then do; output; end; run; proc sort data=x2 out=sigs nodupkey; by sig; run; data sigs2; set sigs; id = catt("id",_n_); run; proc sql noprint; create table final as select a.*, c.id from x a join x2 b on b.group eq a.group join sigs2 c on c.sig eq b.sig order by group, company ; quit; </code></pre> <p>Cheers Rob</p> http://www.runsubmit.com/questions/260/hide-sas-batch-jobs-winxp Hide SAS Batch jobs - WinXP Robert Penridge 2010-05-14T14:36:22Z 2010-06-30T16:11:22Z <p>Hi All</p> <p>I have a scheduled task that runs a SAS program every hour on my WinXP machine. The downside of this is that the job will pop up in the foreground while it is running and disturb me from whatever I'm doing at the time. There is no separate server I can run the job on. Does anyone know how I can make the job run completely hidden in the background? I don't even want to be aware that it is running if possible.</p> <p>I am calling the job from a batch file so there are actually two things to hide. Firstly, the batch job window that appears, and secondly the SAS window that appears. Using the -ICON startup parameter I've managed to at least keep SAS from opening the full IDE but even then I'd rather not see this at all.</p> <p>I don't need to see the status of the job while it is running as I parse the log file after the job has run and the batch file also creates logs so I have full visibility anyway.</p> <p>Any suggestions would be great!</p> <p>Thanks Rob</p> http://www.runsubmit.com/questions/292/determining-uniqueness-of-an-email Determining "Uniqueness" of an email Robert Penridge 2010-06-17T16:51:44Z 2010-06-17T18:28:17Z <p>Hi All</p> <p>I am trying to count how many unique visitors have posted to a site based on email address. The problem is that there is no email address verification so any typos in email address will be captured.</p> <p>I would like to treat the following as different email addresses as there is a high chance of them being different people:</p> <pre><code>kris_77@hotmail.com kris_78@hotmail.com kris_87@hotmail.com kris_88@hotmail.com </code></pre> <p>But the following I would like to treat as separate because the email address is more original/unique:</p> <pre><code>john.fox@hotmail.com jon_fax@hotmail.com </code></pre> <p>Any suggestions for this kind of procedure?</p> <p>Thanks Rob </p> http://www.runsubmit.com/questions/289/labeling-datetime-axis-with-gplot Labeling datetime axis with gplot Robert Penridge 2010-06-14T20:07:16Z 2010-06-17T17:52:37Z <p>Hi All </p> <p>I have a simple line plot that shows values over a period of a few days. I would like to show the days labelled on the major tickmarks and the time of day (hours) labelled on the minor tickmarks.</p> <p>Does anybody have a good way of doing this?</p> <p>Thanks Rob</p> http://www.runsubmit.com/questions/22/how-to-change-char-date-values-into-date9-format/287#287 Answer by Robert Penridge for How to change char Date values into DATE9. format? Robert Penridge 2010-06-08T14:31:18Z 2010-06-08T14:31:18Z <p>It looks like the conversion part of the question has already been answered but if you want to calculate age <em>correctly</em> then it is not as straightforward as it seems. You can use the %intfull() macro from this post though to do this.</p> <p><a href="http://www.runsubmit.com/questions/81/finding-the-of-days-between-two-dates" rel="nofollow">http://www.runsubmit.com/questions/81/finding-the-of-days-between-two-dates</a></p> <p>Cheers Rob</p> http://www.runsubmit.com/questions/284/proc-freq-output-dataset-not-showing-cum-percentages Proc Freq output dataset not showing cum percentages Robert Penridge 2010-06-08T00:49:18Z 2010-06-08T00:52:12Z <p>Can anyone tell me why I don't get a column in the output dataset showing cumulative percentages?</p> <pre><code>data test; a = 1; output; output; a = 2; output; run; proc freq data=test order=freq ; tables a / out=freq missing cumcol; run; </code></pre> <p>Thanks Rob</p> http://www.runsubmit.com/questions/284/proc-freq-output-dataset-not-showing-cum-percentages/285#285 Answer by Robert Penridge for Proc Freq output dataset not showing cum percentages Robert Penridge 2010-06-08T00:52:12Z 2010-06-08T00:52:12Z <p>Oops found it:</p> <pre><code>proc freq data=test order=freq noprint; tables a / out=freq missing outcum; run; </code></pre> http://www.runsubmit.com/questions/279/how-do-i-determine-which-of-compress-binary-or-compress-y-will-produce-the-be/280#280 Answer by Robert Penridge for How do I determine which of compress = binary or compress = y will produce the better compression rate? Robert Penridge 2010-06-05T00:48:22Z 2010-06-05T00:48:22Z <p>Taken from SAS Online Doc. I'd provide the link but I can't figure out how =/</p> <p><strong>compress=y (aka compress=char):</strong> Use this compression algorithm for character data.</p> <p><strong>compress=binary:</strong> This method is highly effective for compressing medium to large (several hundred bytes or larger) blocks of binary data (numeric variables). Because the compression function operates on a single record at a time, the record length needs to be several hundred bytes or larger for effective compression.</p> <p>Sounds like you would use binary on a very wide dataset used for analysis with lots of numeric/binary flags. When in doubt, test it both ways and go with the best =)</p> <p>Cheers Rob</p> http://www.runsubmit.com/questions/273/delay-resolution-of-macro-variable-in-view-definition Delay resolution of macro variable in view definition Robert Penridge 2010-06-01T16:25:27Z 2010-06-02T15:56:53Z <p>Hi All</p> <p>I want to create a view - it doesn't really matter if it's a datastep or SQL view - that delays resolving any macro variables in the definition until the view is actually used (ie. not when the view is defined). The reason for this is that I don't want to have to run the view definition to redefine it every time the value of the macro variable changes. Is this possible?</p> <p>I was thinking something like the below should work but can't get it working. </p> <pre><code>%let xx = 100,101,102; data x; myval = 102; output; myval = 103; output; run; data test / view=test; set x; is_in_list = myval in (resolve('&amp;xx')); run; </code></pre> <p>Thanks! Rob</p> http://www.runsubmit.com/questions/273/delay-resolution-of-macro-variable-in-view-definition/276#276 Answer by Robert Penridge for Delay resolution of macro variable in view definition Robert Penridge 2010-06-01T17:22:52Z 2010-06-01T17:22:52Z <p>Here's an easier to use solution (than my other answer) that uses formats instead of macro variables. It achieves the same result but it simpler to understand. Instead of updating the macro variable you just update a format.</p> <pre><code>data x; myval = 102; output; myval = 103; output; run; proc format; value bump_format 100,102,103 = 1 other=0; run; data test / view=test; set x; is_in_list = cats(put(myval,bump_format.)); run; data _null_; set test; put _all_; run; proc format; value bump_format 1,2,4 = 1 other= 0; run; data _null_; set test; put _all_; run; </code></pre> http://www.runsubmit.com/questions/273/delay-resolution-of-macro-variable-in-view-definition/275#275 Answer by Robert Penridge for Delay resolution of macro variable in view definition Robert Penridge 2010-06-01T16:55:27Z 2010-06-01T16:55:27Z <p>Ok, not the most straightforward way but I found I could use the macro in operator (after first defining it with the minoperator system option) and then wrap it in a %eval, and a resolve. Complicated though so I'm not too sure if it's worth the tradeoff - anyone got a better technique?</p> <pre><code>option minoperator; data x; myval = 102; output; myval = 103; output; run; data test / view=test; set x; is_in_list = resolve(cats('%eval(',myval,'#&amp;xx',')')); run; %let xx = 100 101 102; proc print data=test; run; %let xx = 1 2 4; proc print data=test; run; </code></pre> http://www.runsubmit.com/questions/267/publishing-to-webdav-with-package-call-routines/274#274 Answer by Robert Penridge for Publishing to WebDAV with PACKAGE CALL routines Robert Penridge 2010-06-01T16:40:01Z 2010-06-01T16:40:01Z <p>Hi Will</p> <p>In the past I have found using FTP to be up to 6x faster than some internal SAS transfer methods such as proc download. The call package routines may suffer from the same problems although I haven't used them before. If you are willing to create the files locally then transfer the saved files you may find it faster. This method may also be easier to work with and debug.</p> <p>You can you either the <a href="http://support.sas.com/documentation/cdl/en/movefile/59598/HTML/default/a001021283.htm" rel="nofollow">FTP filename statment</a> in SAS or roll your own FTP script and submit is like so (assuming Win):</p> <pre><code>x "ftp -n -s:"ftpscript.txt 10.1.1.1"; </code></pre> <p>Cheers Rob</p> http://www.runsubmit.com/questions/264/joining-views-with-indexes-in-proc-sql Joining views with indexes in proc SQL Robert Penridge 2010-05-26T21:51:34Z 2010-05-27T13:56:21Z <p>Hi All</p> <p>I have two views, app, and app_status. Each view simply concatenates monthly datasets like so:</p> <pre><code>create view app as select * from app_200901 outer union corresponding select * from app_200902 outer union corresponding ... select * from app_201004 outer union corresponding select * from app_201005; create view app_status as select * from app_status_200901 outer union corresponding select * from app_status_200902 outer union corresponding ... select * from app_status_201004 outer union corresponding select * from app_status_201005; </code></pre> <p>Each <em>TABLE</em> (ie. app200901 or app_status_200901, etc.) is indexed on app_id. When querying either view the indexes on the tables are used. For example the following is fine:</p> <pre><code>select * from app where app_id = 123 </code></pre> <p>However, if I cannot find a way to make SAS use the indexes when joining the two views together. For example:</p> <pre><code>select a.*, b.status from app a join app_status b on b.app_id eq a.app_id </code></pre> <p>In my mind this should work. In reality it doesn't =). The views contain almost 100 million records each so performance is important. </p> <p>Any suggestions on how I can join these tables faster!?</p> <p>Thanks Rob</p> http://www.runsubmit.com/questions/258/formats-not-found-loaded/259#259 Answer by Robert Penridge for Formats not found/loaded Robert Penridge 2010-05-10T16:47:04Z 2010-05-10T16:47:04Z <p>Howdy</p> <p>You may need to ensure that your custom formats are being loaded into the search path that SAS uses to search for formats. </p> <pre><code>libname my_fmts "c:\sasdir\my_formats"; options fmtsearch = (work my_fmts library); </code></pre> <p>The above code will tell SAS to search for formats first in the work library, then in the my_fmts library, then in the default SAS library.</p> <p>Cheers Rob</p> http://www.runsubmit.com/questions/243/loop-across-a-list-of-strings-ie-foreach-loop/246#246 Answer by Robert Penridge for loop across a list of strings (ie. foreach loop) Robert Penridge 2010-04-18T20:09:43Z 2010-04-25T21:38:46Z <p>I have a couple of macros in my macro autocall library that I use to perform this task. I've listed them below. The macro I have written that will do what you need is called %list_parse. It requires a supporting macro called %nWords so I have also listed that below.</p> <p>Oh I should also note that in SAS 9.2 I believe there's now a new built in function to count the number of words in a string, and about time too!</p> <pre><code>/***************************************************************************** ** PROGRAM: NWORDS.SAS ** ** RETURNS THE NUMBER OF WORDS IN A STRING. ** ** PARAMETERS: ** iSTR : THE STRING TO PROCESS. ** iDELIMITERS: OPTIONAL. A LIST OF CHARACTERS TO USE AS DELIMITERS. ** THE DEFAULT IS SAME AS THE %SCAN MACRO. ** *****************************************************************************/ %macro nwords(iStr=, iDelimiters= ); %local word cnt; %let cnt = 0; /* ** IF THE USER SPECIFIED THEIR OWN DELIMITERS THEN USE ** THE USER SPECIFIED, ELSE USE THE %SCAN MACRO'S DEFAULT */ %if "%str(&amp;iDelimiters)" ne "%str()" %then %do; %let word = %scan(%str(&amp;iStr), 1,%str(&amp;iDelimiters)); %end; %else %do; %let word = %scan(%str(&amp;iStr), 1); %end; %do %while ("&amp;word" ne ""); %let cnt = %eval(&amp;cnt + 1); %if "%str(&amp;iDelimiters)" ne "%str()" %then %do; %let word = %scan(%str(&amp;iStr), %eval(&amp;cnt + 1),%str(&amp;iDelimiters)); %end; %else %do; %let word = %scan(%str(&amp;iStr), %eval(&amp;cnt + 1)); %end; %end; &amp;cnt %mend; %put %nWords(iStr=this is); /***************************************************************************** ** PROGRAM: LIST_PARSE.SAS ** ** STORE EACH WORD OF THE STRING INTO IT'S OWN MACRO VARIABLE. ** THE TOTAL NUMBER OF WORDS IN THE STRING IS ALSO SAVED IN A MACRO VARIABLE. ** ** EACH WORD OF THE STRING IS STORED TO ITS OWN MACRO VARIABLE. THE NAMES ** ARE IN THE FORMAT &lt;PREFIX&gt;1 .. &lt;PREFIX&gt;N. ** ** PARAMETERS: ** iSTRING : THE ISTRING TO PROCESS. ** iPREFIX : THE PREFIX TO USE FOR STORING EACH WORD OF THE ISTRING TO ** ITS OWN MACRO VARIABLE (AND THE TOTAL NUMBER OF WORDS). ** iDELIMITERS: OPTIONAL. A LIST OF CHARACTERS TO USE AS DELIMITERS. ** THE DEFAULT IS SAME AS THE %SCAN MACRO. *****************************************************************************/ %macro list_parse(iStr=, iPrefix=, iDelimiters= ); %local cnt nWords word; %let nWords = %nWords(iStr=%str(&amp;iStr),iDelimiters=&amp;iDelimiters); %do cnt = 1 %to &amp;nWords; %if "%str(&amp;iDelimiters)" ne "%str()" %then %do; %let word = %scan(%str(&amp;iStr), &amp;cnt, %str(&amp;iDelimiters)); %end; %else %do; %let word = %scan(%str(&amp;iStr), &amp;cnt); %end; %global &amp;iPrefix.&amp;cnt ; %let &amp;iPrefix.&amp;cnt = &amp;word ; %end; %global &amp;iPrefix; %let &amp;iPrefix = &amp;nWords ; %mend; /* ** EXAMPLES */ %list_parse(iStr=this is a test,iPrefix=myTest); %put &amp;myTest &amp;myTest1 &amp;myTest2 &amp;myTest3 &amp;myTest4; %macro example2; %local i; %do i = 0 %to &amp;myTest; %put &amp;&amp;myTest&amp;i; %end; %mend; %example2; </code></pre> <p>You can also call these macros from within datasteps or SQL statements or anywhere else you feel like. If doing so in datasteps or SQL statements you will need to call them using the resolve function.</p> <p>Also note that if you want to use a comma as a delimiter you should pass it in using the %bquote() macro function.</p> <p>Cheers Rob</p> http://www.runsubmit.com/questions/248/suppressing-results-output-with-proc-print-and-ods Suppressing results output with proc print and ODS Robert Penridge 2010-04-22T14:22:02Z 2010-04-23T01:36:10Z <p>Hi All</p> <p>Is it possible to suppress the printing of results to the results window while still using proc print to create the HTML file below?</p> <pre><code>filename htmlout "c:\temp.html"; ods html body=htmlout(title="Title1") style=normal; ods listing close; proc print data=sashelp.class noobs label ; var name sex age height weight; run; ods listing; title; ods html close; </code></pre> <p>Thanks Rob</p> http://www.runsubmit.com/questions/235/draw-pairs-samples-from-a-database-repeatedly/249#249 Answer by Robert Penridge for Draw pairs samples from a database repeatedly Robert Penridge 2010-04-23T00:50:23Z 2010-04-23T00:50:23Z <p>I think you are looking for something like this:</p> <pre><code>data x; input a b c unique_id; datalines; 1 2 2 101 4 5 1 102 4 5 2 103 1 2 3 104 2 3 4 105 5 6 4 106 1 2 3 107 1 3 2 108 run; proc sort data=x; by a b c; run; data y; set x; by a b c; if not (first.c and last.c) then do; put "OBS" _n_ "IS NOT UNIQUE " _all_; end; else do; put "OBS" _n_ "IS UNIQUE " _all_; end; run; </code></pre> http://www.runsubmit.com/questions/244/dynamic-sasv9-2-generated-objects-in-word-documents/245#245 Answer by Robert Penridge for Dynamic SAS(v9.2) generated objects in Word Documents Robert Penridge 2010-04-18T19:57:42Z 2010-04-18T19:57:42Z <p>How about this workflow:</p> <ol> <li><p>Separate your code so that it's in two parts. Part one creates/updates the data. Part two reads the data and creates the document.</p></li> <li><p>Create your documents for the first time by running both of your programs.</p></li> <li><p>Open your word doc and manually arrange everything so you have the exact look you are after. It's a good idea to keep a backup of this file. </p></li> <li><p>Next time you want to update it, just run the part of your program that udpates the data. Then the links in the word doc should refresh it automatically. </p></li> </ol> <p>I use this approach all the time but I usually report to Excel. Normally I'll just write the program so that it sends the data I need to excel. I'll manually design the charts in excel and get the exact look. Then I'll remove all of the data from the workbook (but leave the charts, titles, etc. and save the result as a template for my report. From there all I ever have to do is send the data I want to excel and the charts are automatically updated. You could also use this approach then link to those charts from word.</p> <p>Cheers Rob</p> http://www.runsubmit.com/questions/196/disabling-sas-modules Disabling SAS modules? Robert Penridge 2010-01-09T23:54:00Z 2010-01-12T15:41:33Z <p>I have SAS/ACCESS licensed (among other modules) but want to disable it in order to simulate someone else's environment? It would also be helpful for answering some of the questions on this site. Is anyone aware of a way to do this?</p> http://www.runsubmit.com/questions/33/is-a-hash-object-faster-than-an-array/195#195 Answer by Robert Penridge for Is a Hash object faster than an Array? Robert Penridge 2010-01-09T23:36:36Z 2010-01-09T23:36:36Z <p>My understanding is that there are additional overheads when working with a hash object. These can be broken down into 3 main areas:</p> <ol> <li>Creating the hash object.</li> <li>Determining where to store data in the hash object.</li> <li>Determining where to retrieve data from in the hash object.</li> </ol> <p>The hash object takes its name from the hashing algorithm that is used to calculate where an observation will be stored in the hash table (ie. in memory). The hashing algorithm is extremely fast though and the result of applying the algorithm to a key value is the exact location in memory it is stored. This means that the hashing algorithm needs to be applied to a key value any time you want to store or retrieve information from the hash table. </p> <p>When dealing with an array the hash algorithm is not required because you explicitly specify the index from the array that you want to store or retrieve information from. The location in memory can be almost instantly determined once the index is supplied. This assumes you already know the array index that contains the data you require.</p> <p>Both hash tables and arrays are loaded into memory. If you don't have sufficient memory the performance of a hash table can severely suffer. (<a href="http://support.sas.com/kb/34/193.html" rel="nofollow">http://support.sas.com/kb/34/193.html</a>) If you wanted to create hash tables in earlier versions of SAS prior to the existence of the hash object then you had to create it manually using arrays. </p> http://www.runsubmit.com/questions/81/finding-the-of-days-between-two-dates/193#193 Answer by Robert Penridge for Finding the # of days between two dates? Robert Penridge 2010-01-08T05:30:31Z 2010-01-08T05:30:31Z <p>Hi. I know this question has already been answered but I thought I would present this as an alternative as the original question was a little ambiguous. For example, say you wanted to calculate a person's age (the number of full years inbetween now and the day they were born). You cannot <em>easily</em> use intck to do this <em>correctly</em>. Below I have included a macro function that I use to achieve this and similar purposes... ie. how many months has a customer been with us. Have they been with us for a full year. etc...</p> <p>This macro function has been written in pure macro code so that it can be called from within a datastep or SQL function almost as easily as any in-built SAS function. I suggest putting it in your macro autocall library.</p> <pre><code>/****************************************************************************** ** PROGRAM: MACRO.INTFULL.SAS ** ** DESCRIPTION: SIMILAR TO INTCK EXCEPT THIS RETURNS THE FULL NUMBER OF ** PERIODS INBETWEEN THE TWO DATES YOU SPECIFY. IE. ** ** INTCK INTFULL ** DATE1 DATE2 INTERVAL RESULT RESULT= ** --------- --------- -------- ------ ------- ** 31-DEC-07 01-JAN-08 YEAR 1 0 ** 31-DEC-07 30-DEC-08 YEAR 1 0 (1 DAY SHORT OF A FULL YEAR) ** 31-DEC-07 31-DEC-08 YEAR 1 1 ** 20-JUL-07 18-OCT-07 MONTH 3 2 (2 DAYS SHORT OF 3 FULL MTHS) ** ** YOU CAN PASS IN ANY INTERVAL (YEAR/MONTH/DAY/ETC) THAT THE INTNX ** FUNCTION ACCEPTS. ** ******************************************************************************* ** VERSION: ** 1.0 ON: 05-JAN-08 BY: ROBERT PENRIDGE ** CREATED. ******************************************************************************/ %macro intfull(iInterval=,iStart_dt=,iEnd_dt=); %local first_dt second_dt cnt; /* ** ENSURE THAT WE USE THE LOWEST DATE PROVIDED AS THE START DATE */ %if &amp;iStart_dt le &amp;iEnd_dt %then %do; %let first_dt = &amp;iStart_dt; %let second_dt = &amp;iEnd_dt; %end; %else %do; %let first_dt = &amp;iEnd_dt; %let second_dt = &amp;iStart_dt; %end; %let cnt = 0; %let first_dt = %sysfunc(intnx(&amp;iInterval,&amp;first_dt,1,same)); %do %while (&amp;first_dt le &amp;second_dt); %let cnt = %eval(&amp;cnt + 1); %let first_dt = %sysfunc(intnx(&amp;iInterval,&amp;first_dt,1,same)); %end; &amp;cnt %mend; /* ** EXAMPLE 1. USE IN MACRO CODE */ %let start_dt = %sysfunc(mdy(07,1,2008)); %let end_dt = %sysfunc(mdy(08,1,2009)); %put %intfull(iInterval=year,iStart_dt=&amp;start_dt,iEnd_dt=&amp;end_dt); /* ** EXAMPLE 2. USE WITHIN A DATASTEP USING VALUES FROM THE DATASET. ** NOTE I HAVE 'ACCIDENTALLY' MADE THE START DATE LATER ** THAN THE END DATE AND THE FUNCTION STILL WORKS. */ data xx; start_dt = mdy(7,20,2008); end_dt = mdy(10,18,2008); full_months_between = resolve(cats('%intfull(iInterval=month,iStart_dt=',start_dt,',iEnd_dt=',end_dt,')')); put _all_; run; /* ** EXAMPLE 3. USE WITHIN AN SQL STATEMENT. */ proc sql noprint; create table zz as select start_dt, end_dt, resolve(cats('%intfull(iInterval=month, iStart_dt=',start_dt, ',iEnd_dt=',end_dt,')')) as full_months_between from xx; quit; </code></pre> http://www.runsubmit.com/questions/169/sas-coding-standards/188#188 Answer by Robert Penridge for SAS Coding Standards Robert Penridge 2010-01-06T06:46:40Z 2010-01-06T06:46:40Z <p>Sometimes less <strong>is not more</strong>!</p> <p>Don't be afraid to put in that extra line containing the word <strong>run;</strong> at the end of your data step, or that <strong>quit;</strong> at the end of your <strong>proc sql</strong>, or even spreading out that <strong>proc means</strong> step across 2 or 3 lines instead of cramming it all on one 150 character line. Fine, it's your code and right now you know what it does but one day someone else is going to read your code and... </p> <p><strong>...it is much easier to write code then it is to read code.</strong> </p> <p>Don't make them devote that extra bit of thought power to fill in the missing blanks. Write code as if you are writing it for somebody else to read. And make it as effortless as possible for them, because they're already trying to balance 12 other things in their head without the added difficulty of mentally adding in your missing <strong>end;</strong> statements.</p> http://www.runsubmit.com/questions/185/theta-symbol-in-a-sas-label/186#186 Answer by Robert Penridge for Theta Symbol in a SAS Label? Robert Penridge 2010-01-05T02:55:45Z 2010-01-05T02:55:45Z <p>As far as I can gather you can pretty much assign any character to a SAS label. It's more a case of whether SAS will display the expected character back to you, or if it will substitute it with a question mark instead. From some very quick tests I could only get SAS labels to display correctly with the ASCII characters 0-255. If your greek letter is in that list then you're golden. If not then I think it may be a problem. I know the top 255 will display correctly as the label both when you print the dataset and open it for browsing. Good luck.</p> <pre><code>** ** PRINT LIST OF AVAILABLE ASCII CHARACTERS *; data _null_; do i = 0 to 255; ascii_symbol = byte(i); put i ascii_symbol; end; run; ** ** CREATE A TABLE WITH AN ASCII LABEL AND ** PRINT IT ENSURING THE LABEL IS SHOWN. *; data x; label y = "%sysfunc(byte(240))"; y = "blah"; run; proc print data=x label; run; </code></pre> http://www.runsubmit.com/questions/339/how-to-find-the-end-of-week-date-for-a-given-date/348#348 Comment by Robert Penridge Robert Penridge 2010-07-29T14:41:05Z 2010-07-29T14:41:05Z Hi Matt, I believe you would want to keep the we_day that Mark has used otherwise it will only ever be useful for weeks starting on Saturday. Give it a default value though so it is an optional parameter. http://www.runsubmit.com/questions/332/sas-graph-educational-resources/333#333 Comment by Robert Penridge Robert Penridge 2010-07-23T17:00:54Z 2010-07-23T17:00:54Z Good links too Sarath - thanks.. http://www.runsubmit.com/questions/332/sas-graph-educational-resources/338#338 Comment by Robert Penridge Robert Penridge 2010-07-23T17:00:39Z 2010-07-23T17:00:39Z Chose this as the answer due to the huge variety of samples provided. http://www.runsubmit.com/questions/324/finding-similar-groups/329#329 Comment by Robert Penridge Robert Penridge 2010-07-16T16:34:19Z 2010-07-16T16:34:19Z Hi Sarath - Yes this was my first attempt at solving this problem too but I realised there are several downsides to this approach. 1) More maintainence - if you add a new group you need to change the code. 2) It will run more slowly on large datasets. http://www.runsubmit.com/questions/289/labeling-datetime-axis-with-gplot/293#293 Comment by Robert Penridge Robert Penridge 2010-06-17T19:18:14Z 2010-06-17T19:18:14Z Great thanks for this. I ended up taking a similar approach but using proc template, overlay and boxplots which I'll post as soon as I get the time. However, I think your answer addresses the question better than my response will so thanks again! http://www.runsubmit.com/questions/260/hide-sas-batch-jobs-winxp/283#283 Comment by Robert Penridge Robert Penridge 2010-06-07T16:34:35Z 2010-06-07T16:34:35Z Thanks for the suggestion but this also leaves the ICON window in the foreground on the screen. To test this I created a sas file called endless_loop.sas which contained the following &lt;START CODE&gt; data z;do while (1);end;run; &lt;END CODE&gt; I then scheduled a job using your suggested settings and ran this file. I suspect that your test program may have been running so fast you didn't even see this window appear. Are you able to test with my code and let me know if you experience different results? Thanks, Rob http://www.runsubmit.com/questions/273/delay-resolution-of-macro-variable-in-view-definition/278#278 Comment by Robert Penridge Robert Penridge 2010-06-02T16:43:14Z 2010-06-02T16:43:14Z Thanks William. I've accepted this one as it's the simplest method that answers the question. http://www.runsubmit.com/questions/264/joining-views-with-indexes-in-proc-sql/266#266 Comment by Robert Penridge Robert Penridge 2010-05-27T21:56:58Z 2010-05-27T21:56:58Z Yup - works a treat! I wish I could vote this up more! Thanks a tonne. http://www.runsubmit.com/questions/264/joining-views-with-indexes-in-proc-sql/266#266 Comment by Robert Penridge Robert Penridge 2010-05-27T14:24:56Z 2010-05-27T14:24:56Z I like the sound of this. I'll try this first and if this doesn't work then I'll probably go with your other macro driven response. Thanks for the good suggestions! http://www.runsubmit.com/questions/251/large-character-field-sizes-in-sas/252#252 Comment by Robert Penridge Robert Penridge 2010-04-25T21:35:27Z 2010-04-25T21:35:27Z Yes I think that's the approach I'll have to take. Thanks. http://www.runsubmit.com/questions/251/large-character-field-sizes-in-sas/252#252 Comment by Robert Penridge Robert Penridge 2010-04-24T19:32:50Z 2010-04-24T19:32:50Z OP here. BIG_FAT_COLUMN contains an XML file. Usually under 32k but often over. Will be using a map file generated by the SAS XML Mapper to read the contents into SAS datasets and then work with them. http://www.runsubmit.com/questions/199/maximum-size-of-a-sas-script/200#200 Comment by Robert Penridge Robert Penridge 2010-01-16T02:41:25Z 2010-01-16T02:41:25Z Yes this has happened to me before and caused all sorts of problems! I discovered it was because I had accidentally hit the F4 key after submitting a program with the F3 key! The F4 key has the default behavior of 'recall' which places the code just run back into the program editor wherever the cursor happens to be. Very dangerous if you ask me and surprisingly difficult to realise. I removed the action from the F4 key as soon as I figured this out. http://www.runsubmit.com/questions/33/is-a-hash-object-faster-than-an-array/44#44 Comment by Robert Penridge Robert Penridge 2010-01-15T23:57:53Z 2010-01-15T23:57:53Z both hash tables AND arrays are stored in memory and would require approximately the same amount of space. hash tables do not get written to disk unless you run out of memory. i'm not sure how investing in a new hardware applies here - can you please try to clarify http://www.runsubmit.com/questions/169/sas-coding-standards/209#209 Comment by Robert Penridge Robert Penridge 2010-01-14T21:15:06Z 2010-01-14T21:15:06Z agreed because it is likely that everyone on your team is using a different editor all of which are setup to show tabs in a different manner http://www.runsubmit.com/questions/26/unduplicating-records-within-a-sas-dataset/27#27 Comment by Robert Penridge Robert Penridge 2010-01-11T21:14:14Z 2010-01-11T21:14:14Z Also if the entire observation contains duplicate values (not just duplicate keys) then you can use the &quot;noduprecs&quot; keyword instead of the &quot;nodupkey&quot; keyword. There are a few gotchas with the &quot;noduprecs&quot; approach though so I suggest reading about it in the online doc prior to using it: <a href="http://support.sas.com/documentation/cdl/en/proc/61895/HTML/default/a000146878.htm#a003070995" rel="nofollow">support.sas.com/documentation/cdl/en/proc/61895/&hellip;</a>