Professional Documents
Culture Documents
10 Steps To Easier SAS Code Maintenance
10 Steps To Easier SAS Code Maintenance
ABSTRACT
Part of the authors job at CIGNA is to produce on a yearly basis a number of rates used in national healthcare quality surveys and accreditation performance measures. Each year when the revised specs came out, she got tired of having to update processes manually, hunting through programs for diagnosis codes and dates that needed to be changed, copying and pasting the same updates and code blocks so many times she lost count, and then inevitably finding out shed missed a spot when the program either bombed, or worse ran all the way through but returned last years data instead of this years or outdated diagnosis codes. Then when the revisions to the revisions came out and those revised revisions begot new revisions as well, she had to keep going through the same tedious process. This paper describes how to make yearly code maintenance tasks easier in 10 steps, using simple organization techniques, appropriate documentation, macro variables, and parameterized macros. 1. Break large processes into smaller steps. 2. Number programs. 3. Document using comments. 4. Document using program headers. 5. Create an initial startup program. 6. Create a final cleanup program. 7. Use macro variables for date selection criteria. 8. Use macro variables for file naming. 9. Use parameterized macros for similar processes. 10. Use macro variables for long lists that need frequent updating/referencing.
INTRODUCTION
Some of the sections of this paper are targeted toward people in the health insurance industry who work with NCQA-like quality measures which tend to have similarities and variations around a common theme. Such measures often include long lists of diagnoses and procedural codes which get updated on a yearly (or more frequent) basis. However, the larger point of the paper is applicable to many different fields: Think about how to organize programs and process flow before beginning a project (similar to outlining a paper before writing it), use macro variables to store and reference regularly updated values (such as dates) in a consolidated fashion, and minimize coding where possible with parameterized macros.
NUMBER PROGRAMS
Once the process flow is organized into smaller programs, number programs in the order in which they should be run. This is like creating a table of contents or an index. Store each process flow in its own folder.
Including field lengths and file sizes in the data dictionary can help the programmer identify at a glance which fields were inadvertently created or extracted with a longer length than needed to store the data (a 200 length field used to store an 8 character string can have a large impact on the size of a file). This information can be used to edit programs later to decrease table sizes and minimize storage space, which is an important consideration when dealing with already large data sets.
1,3,14,16
7,8,15 2
1,3,10,14
7*,8,13
include discharges with principal diagnosis code specified: hypertension CHF angina
transfers transfers cardiac procedure codes in any field *For 7 only, also exclude kidney disease diagnoses if accompanied by hemodialysis procs
11,12 2
include discharges with principal diagnosis code specified: bacterial pneumonia UTI include discharges with principal or secondary diagnosis code for perforation or abscess of appendix include discharges with principal diagnosis code for COPD certain diagnoses qualify only if accompanied by secondary diagnosis
transfers immunocompromised state proc codes immunocompromised state diagnoses *For 11, also exclude anemia principal or secondary diagnoses *For 12, also exclude principal or secondary kidney disorder diagnoses transfers
15
16
include discharges with principal diagnosis code for asthma include discharges with principal or secondary diagnosis code for diabetes AND procedure code for lower-extremity amputation
transfers
Doing such an analysis can identify pieces which the developer can convert to parameterized macros to save time coding. Not only does this save time coding initially for the developer, it also saves time maintaining the code, allowing the programmer to revise a single macro rather than copying and pasting the revision in many different places across several programs. In this case, each measure gets its own program, and initial and cleanup programs are also created. Here is an example of the parameterized macro transfer which is then called twice (once for managed care and once for ppo) by all 16 programs in creating the numerators: %macro transfer(filename=)/STORE SOURCE; /*identify and delete transfers from numerator*/ CREATE TABLE &filename._TRANS AS SELECT B.conf_id, B.admit_dt, A.disch_dt FROM PQI.&filename A JOIN PQI.&filename B ON A.rhmo=B.rhmo AND A.bkey=B.bkey AND A.disch_dt BETWEEN B.admit_dt AND intnx('DAY',B.admit_dt,-1) /*re-admitted within 24 hours of discharge date*/ WHERE A.conf_id <> B.conf_id AND A.src_sys_prov_id <> B.src_sys_prov_id /*transferred from different facility*/ ; DELETE FROM PQI.&filename WHERE conf_ID IN (SELECT conf_id FROM &filename._TRANS) ; %mend transfer;
%let markets = %str('WA','OR','CA','CO','TN','FL','SC','MD','DC','OH','NJ','NY','CT'); /*eValue8 markets*/ %let diabetes = %str('25000','25001','25002','25003','25010','25011','25012','25013','25020','2502 1','25022','25023','25030','25050','25051','25052','25053','25060','25061','25062' ,'25063','25070','25071','25072','25073','25080','25031','25032','25033','25040',' 25041','25042','25043','25081','25082','25083','25090','25091','25092','25093'); /*diabetes diagnosis codes, PQI 1,3,14,16*/ For long lists of codes with an ECT available, use the SQL procedure to select into macro variables that are easy to reference in multiple places, eliminating the need to join to and select from the ECT more than once. When in development, use system options SYMBOLGEN and MPRINT to check the log to make sure that the macro variables resolve correctly. SELECT code INTO: opnaiprev separated by '","' /*outpatient, non-acute inpatient revenue proc codes*/ FROM ref.ect WHERE description in('outpatient','nonacute_inpatient') AND typeofcode='RevCode' AND tablename='CDC_C' ; SELECT code INTO: aipedcpt separated by '","'/*acute inpatient, ed cpt proc codes*/ FROM ref.ect WHERE description in('acute_inpatient','ed') AND typeofcode='CPT' AND tablename='CDC_C' /*ophthalmological services not needed for non-diabetic measures - 5,7,8,15*/ ; Making use of macro variables makes the resulting code much shorter and easier to understand; instead of having the same long list of diagnosis codes repeated multiple times below, it is easier to see what the WHERE clause is actually doing without having to scroll: WHERE svc_dt BETWEEN "01jan&yearp"d AND "31dec&year"d /*current year or year prior*/ AND (diag_cd1 IN (&diagcd) OR diag_cd2 IN (&diagcd) OR diag_cd3 IN (&diagcd)) /*primary or secondary diagnosis code*/ AND (proc_cd IN("&aipedcpt") /*acute inpatient or ED cpt codes*/ OR (proc_cd IN("&aipedrev") /*3-byte rev codes for mco, 4-byte for ppo*/
Putting together the macro variables with the parameterized macros, the process of building denominators and numerators to create the first measure looks like this:
Instead of having to repeat blocks of nearly identical code, using parameterized macros for similar processes greatly shortens the amount of code requiring maintenance.
CONCLUSIONS
Using simple techniques to organize process flow, macro variables to minimize hard coding, and parameterized macros along with even minimal documentation can greatly improve ease of code maintenance. This approach facilitates code maintenance in three ways: by making portions of frequently updated code easier to locate (like having a good filing system), minimizing hard coding of dates and lists of codes, and by decreasing the overall volume of code created in the first place.
REFERENCES:
SAS Institute Inc. 2009. SAS 9.2 Macro Language Reference. Cary, NC: SAS Institute, Inc. Patridge, C. Best Practices: Using SAS Effectively/Efficiently. HASUG presentation 2/24/2011. Rhodes, D. If You Have Programming Standards, Please Raise Your Hand: An Everymans Guide. http://www.nesug.org/Proceedings/nesug10/ma/ma10.pdf (5/31/2011).
ACKNOWLEDGMENTS
SAS and all other SAS Institute Inc. product or service names are registered trademarks or trademarks of SAS Institute Inc. in the USA and other countries. indicates USA registration.
CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the author at: Jessica Hampton CIGNA Corporation 900 Cottage Grove Rd Bloomfield, CT 06002 Work Phone: (860) 226-1938 Email: Jessica.Hampton@cigna.com Web: http://www.linkedin.com/profile/view?id=40228999&locale=en_US&trk=tab_pro
************************************************