Using Data Set Options in PROC SQL Kenneth W. Borowiak Howard M. Proskin & Associates, Inc., Rochester, NY

Similar documents
The DATA Statement: Efficiency Techniques

DBLOAD Procedure Reference

SAS/FSP 9.2. Procedures Guide

USING PROC SQL EFFECTIVELY WITH SAS DATA SETS JIM DEFOOR LOCKHEED FORT WORTH COMPANY

Simple Rules to Remember When Working with Indexes

Demystifying PROC SQL Join Algorithms

PhUse Practical Uses of the DOW Loop in Pharmaceutical Programming Richard Read Allen, Peak Statistical Services, Evergreen, CO, USA

The Power of PROC SQL Techniques and SAS Dictionary Tables in Handling Data

One-to-One, One-to-Many, and Many-to-Many Joins Using PROC SQL

How to Incorporate Old SAS Data into a New DATA Step, or What is S-M-U?

Stephen M. Beatrous, SAS Institute Inc., Cary, NC John T. Stokes, SAS Institute Inc., Austin, TX

ABSTRACT MORE THAN SYNTAX ORGANIZE YOUR WORK THE SAS ENTERPRISE GUIDE PROJECT. Paper 50-30

Practical Uses of the DOW Loop Richard Read Allen, Peak Statistical Services, Evergreen, CO

Contents. About This Book...1

SAS/ACCESS Interface to R/3

SAS Studio: A New Way to Program in SAS

Exploring DICTIONARY Tables and SASHELP Views

Using the SQL Editor. Overview CHAPTER 11

Not Just Merge - Complex Derivation Made Easy by Hash Object

APPENDIX 4 Migrating from QMF to SAS/ ASSIST Software. Each of these steps can be executed independently.

Undocumented and Hard-to-find PROC SQL Features

SAS Scalable Performance Data Server 4.3 TSM1:

PharmaSUG Poster PO12

Using Data Transfer Services

CV2ODBC Procedure. Overview. CV2ODBC Procedure Syntax APPENDIX 4

A Hands-on Tour Inside the World of PROC SQL

Tales from the Help Desk 5: Yet More Solutions for Common SAS Mistakes Bruce Gilsen, Federal Reserve Board

SAS Data Integration Studio 3.3. User s Guide

Get Started Writing SAS Macros Luisa Hartman, Jane Liao, Merck Sharp & Dohme Corp.

Anatomy of a Merge Gone Wrong James Lew, Compu-Stat Consulting, Scarborough, ON, Canada Joshua Horstman, Nested Loop Consulting, Indianapolis, IN, USA

David Beam, Systems Seminar Consultants, Inc., Madison, WI

Creating and Executing Stored Compiled DATA Step Programs

Full file at

WHAT ARE SASHELP VIEWS?

Debugging 101 Peter Knapp U.S. Department of Commerce

Getting Information from a Table

Dynamic Projects in SAS Enterprise Guide How to Create and Use Parameters

Better Metadata Through SAS II: %SYSFUNC, PROC DATASETS, and Dictionary Tables

10 The First Steps 4 Chapter 2

INTRODUCTION TO SAS HOW SAS WORKS READING RAW DATA INTO SAS

Analytics: Server Architect (Siebel 7.7)

Uncommon Techniques for Common Variables

PharmaSUG China Mina Chen, Roche (China) Holding Ltd.

Locking SAS Data Objects

SAS/Warehouse Administrator Usage and Enhancements Terry Lewis, SAS Institute Inc., Cary, NC

Guide Users along Information Pathways and Surf through the Data

Gary L. Katsanis, Blue Cross and Blue Shield of the Rochester Area, Rochester, NY

chapter 2 G ETTING I NFORMATION FROM A TABLE

Exploring DATA Step Merge and PROC SQL Join Techniques Kirk Paul Lafler, Software Intelligence Corporation, Spring Valley, California

An Introduction to SAS/FSP Software Terry Fain, RAND, Santa Monica, California Cyndie Gareleck, RAND, Santa Monica, California

The SERVER Procedure. Introduction. Syntax CHAPTER 8

SAS Business Rules Manager 1.2

Hidden in plain sight: my top ten underpublicized enhancements in SAS Versions 9.2 and 9.3

Oracle Database 10g: Introduction to SQL

Andrew H. Karp Sierra Information Services, Inc. San Francisco, California USA

SAS Performance Tuning Strategies and Techniques

Data Set Options. Specify a data set option in parentheses after a SAS data set name. To specify several data set options, separate them with spaces.

2) SQL includes a data definition language, a data manipulation language, and SQL/Persistent stored modules. Answer: TRUE Diff: 2 Page Ref: 36

How to Create Data-Driven Lists

BASICS BEFORE STARTING SAS DATAWAREHOSING Concepts What is ETL ETL Concepts What is OLAP SAS. What is SAS History of SAS Modules available SAS

FSEDIT Procedure Windows

Undocumented and Hard-to-find PROC SQL Features

Introduction. Getting Started with the Macro Facility CHAPTER 1

Oracle Database: Introduction to SQL Ed 2

Loading Data. Introduction. Understanding the Volume Grid CHAPTER 2

Base and Advance SAS

Test Bank for Database Processing Fundamentals Design and Implementation 13th Edition by Kroenke

Effectively Utilizing Loops and Arrays in the DATA Step

It s All About Getting the Source and Codelist Implementation Right for ADaM Define.xml v2.0

Producing Summary Tables in SAS Enterprise Guide

CHAPTER 7 Using Other SAS Software Products

Best Practice for Creation and Maintenance of a SAS Infrastructure

Customizing Your SAS Session

capabilities and their overheads are therefore different.

Performance Enhancements to PROC SQL in Version 7 of the SAS System

Sorting big datasets. Do we really need it? Daniil Shliakhov, Experis Clinical, Kharkiv, Ukraine

Programming Beyond the Basics. Find() the power of Hash - How, Why and When to use the SAS Hash Object John Blackwell

Are you Still Afraid of Using Arrays? Let s Explore their Advantages

Join (SQL) - Wikipedia, the free encyclopedia

What s New in SAS Studio?

Optimizing System Performance

CHAPTER 7 Examples of Combining Compute Services and Data Transfer Services

Tweaking your tables: Suppressing superfluous subtotals in PROC TABULATE

Using SAS with Oracle : Writing efficient and accurate SQL Tasha Chapman and Lori Carleton, Oregon Department of Consumer and Business Services

using and Understanding Formats

SAS 9.3 LIBNAME Engine for DataFlux Federation Server

Using SAS Enterprise Guide to Coax Your Excel Data In To SAS

An Introduction to Compressing Data Sets J. Meimei Ma, Quintiles

Are Your SAS Programs Running You? Marje Fecht, Prowerk Consulting, Cape Coral, FL Larry Stewart, SAS Institute Inc., Cary, NC

STATION

PRXChange: Accept No Substitutions Kenneth W. Borowiak, PPD, Inc.

Paper ###-YYYY. SAS Enterprise Guide: A Revolutionary Tool! Jennifer First, Systems Seminar Consultants, Madison, WI

CDISC Variable Mapping and Control Terminology Implementation Made Easy

Indenting with Style

QUEST Procedure Reference

SAS Visual Analytics Environment Stood Up? Check! Data Automatically Loaded and Refreshed? Not Quite

Source. Turning onto a Two-Way Street A Tutorial on The SAS System and ODBC. Data. ODBCdnver

Arthur L. Carpenter California Occidental Consultants, Oceanside, California

If You Need These OBS and These VARS, Then Drop IF, and Keep WHERE Jay Iyengar, Data Systems Consultants LLC

SAS Macro Dynamics - From Simple Basics to Powerful Invocations Rick Andrews, Office of the Actuary, CMS, Baltimore, MD

Transcription:

Using Data Set Options in PROC SQL Kenneth W. Borowiak Howard M. Proskin & Associates, Inc., Rochester, NY ABSTRACT Data set options are an often over-looked feature when querying and manipulating SAS data sets with PROC SQL. This paper explores using the data set options DROP, KEEP, LABEL, SORTEDBY, WHERE, and RENAME in the FROM clause and CREATE TABLE statement of PROC SQL. These options can help facilitate more succinct and efficient code and to create parsimonious and well-labeled data sets. INTRODUCTION Data set options can be tautologically described as options called upon to control the use of a data set and its variables and indices. Data set options such as KEEP, RENAME and LABEL are found within parentheses directly following a data set reference and pertain to only that data set 1. Data set options differ from system options (which influence an entire SAS session) and statement options (which provide instructions in a PROC or DATA step). /* Figure 1 - Examples of SAS Options */ option obs=max; * <-- system option ; proc summary data=sashelp.prdsal2 * statement option --> ; nway; class country year quarter; var actual predict; output out=save.sales_means(label='means of Actual & Predicted Sales') mean= / autoname ; * ^--- data set option ; run; Data set options are an invaluable tool for manipulating, modifying, and adding descriptive properties to data sets. However, applications of data set options are seldom found in the context of PROC SQL in the SAS On-Line doc, SAS provided sample programs and postings on the SAS-L newsgroup. The purpose of this paper is to expose the usefulness of data set options in PROC SQL to help facilitate more succinct and efficient code and to create parsimonious and well-labeled data sets. The specific points covered should be of interest to beginning and intermediate users of PROC SQL. PRELIMINARIES Uses of various data set options in PROC SQL will be presented through a series of examples using three data sets from a fictitious clinical trial. The code which generated the Tx, Scores and Surgery data sets can be found in Appendix 1, along with a partial display of the data sets. The Tx data set contains information on the subject (numeric field with values between 1 and 3000), study center, randomization date and code of received treatment (numeric field with values of 1 or 2). The Scores data set contains information on the subject (character field concatenation of the subject number and study center), visit and numeric scores for parameters A1-A10 and B1-B10. The Surgery data set contains information on the subject, the visit where a surgical procedure was performed and a case record number. DROP and KEEP PROC SQL queries require the SELECT statement to specify the variables to be included in the output destination. The programmer has the option to explicitly state which variables to keep or use the * wildcard as a short-cut to select all fields from some or all tables involved in the query. PROC SQL users are often faced with the dilemma of having to choose between typing in a long list of variables to keep or use the * to select more variables than are actually needed. The dilemma can be alleviated by using the KEEP or DROP data set options in the FROM statement. Suppose that all variables except the scores for the ten B parameters are needed from the Scores the data set. The query could be written 1 See the SAS On-line documentation for a comprehensive list of data set options. 1

succinctly by using the * wildcard and the DROP data set option to remove variables as they are being brought into the query, as demonstrated below in Figure 2. /* Figure 2 - DROP Data Set Option in the FROM Statement */ proc sql; create table only_a_1(label='scores for A Parameters Only') as from Scores(drop=B1-B10); * <-- Note the use of the list range short-cut; /* or */ create table only_a_2(label='scores for A Parameters Only') as from Scores(drop=B1--B10); *<-- Note the use of the name range short-cut; /* or */ create table only_a_3(label='scores for A Parameters Only') as from Scores(drop=B:); * <-- Note the use of the colon modifier; Note the use of the list range (-) short-cut in the DROP data set option reference in the first query. This short-cut refers to a list of variables with a common prefix with an indexed number suffix. The second query makes use of the name range (--) short-cut to refer to all variables in the data set located between B1 and B10. Note the use of the colon modifier in the third query to drop all variables beginning with the letter B. All of the three aforementioned coding short-cuts are not valid in the SELECT statement nor is the colon modifier in the WHERE and HAVING clauses, but they are available when specifying data set options. The KEEP and DROP data set options are also available in the CREATE TABLE statement of PROC SQL. Suppose that the treatment code and randomization date from the Tx data set needs to be joined with the information from the Scores data set. It would be redundant to keep the subject_no and center fields from the Tx data set because the information is captured in the subject_id field from the Scores data set. One way the query could be written is displayed below in Figure 3. /* Figure 3 DROP Data Set Option in the CEATE TABLE statement */ %let label=recorded Scores at Visits with Tx; proc sql; create table scores_tx(label="&label" drop=subject_no center) as from Tx T1, Scores T2 where T1.subject_no=input(substr(subject_id,5),8.) and T1.center=input(substr(subject_id,1,3),8.); As was the case with the queries in Figure 2, the unwanted variables are specified with the DROP data set option in conjunction with the * wildcard rather than explicitly stating the desired ones. However, the unwanted variables omitted from the resulting data set are needed to join the tables. So dropping the variables via a data set option needs to be delayed until the data is written out to the resulting data set. The two examples in this section have demonstrated how the DROP data set option (and implicitly the KEEP data set option) can be used to conveniently and succinctly include fields in a resulting table and reduce the carrying around of unneeded fields. 2

LABEL All of the queries in Figures 2 and 3 employ the LABEL data set option to provide a descriptive title of the data set. Specifying a data set label is a good programming practice, especially for permanent SAS data sets that can be accessed by others. The LABEL data set option should follow the data set reference in the CREATE TABLE or CREATE VIEW statements in PROC SQL. This option has no effect on existing data sets referenced in the FROM statement. SORTEDBY One of the appealing features of PROC SQL is that it does not require data sets to be sorted by the user prior to joining them, especially if there are many data sets involved or some of them are large. So what techniques does SQL use to join tables? There are three types of joins that SQL considers when it needs to match keys from different tables exactly, also known as an equijoin. In general, if the key variable(s) in at least one data set is indexed then an index join is considered first. If the indexed key variable(s) does not succeed in returning a discriminating amount of results (~ <20%) then a merge join is considered. A merge join is similar to a data step merge and may be employed at this point if the SQL optimizer recognizes that the larger of the two data sets being joined is sorted. If the previous condition fails then a hash join is considered. The details of hashing can be found in recent papers by Dorfman et al. [2003, 2004], but simply put it involves loading the smaller of two tables into memory to allow for fast searching on the keys. A hash join is employed at this stage if there is sufficient amount of memory to accept the smaller table. If a hash join can not be performed, the data sets will be sorted and a merge join is employed. A key point is that when PROC SQL develops an efficient strategy to join tables it wants to avoid doing any sorting. The SQL optimizer consults the metadata to determine whether a data set is sorted, and if so, by which fields. However, data sets are sometimes in order without being sorted. For example, the resulting data sets from a PROC SUMMARY statement and DATA step merge (sometimes) are in order by the CLASS and BY variables, respectively, but this information is not captured by the metadata. If these resulting data sets become part of a subsequent multi-table PROC SQL query, they may be unnecessarily sorted if they are too large to be part of a hash join. Superfluous sorting can be avoided by using the SORTEDBY data set option in the FROM statement in PROC SQL. The SORTEDBY data set option provides information regarding by which variables the data set is sorted. To ascertain the join strategy and any sorting the optimizer decides upon to execute a submitted query the PROC SQL statement option _method should be used. This undocumented option by SAS has been examined in an article by Lavery [2005]. The _method option will provide a high-level summary of the methods used to execute the query. A sample of possible codes produced by _method is provided below. Table 1 - Message Codes from _method Code sqxjm sqxjhsh sqxjndx sqxsort Description Merge Join Hash Join Index Join Sort Consider the following query with its associated log where the information from the Surgery data set is joined to the Scores data set when the subject ID and visit number are found in both data sets. /* Figure 4A Query Without the SORTEDBY Data Set Option */ proc sql _method; create table score_surg(label= Scores at Surgery Visits ) as from where Scores T1, Surgery T2 T1.Subject_id=T2.Subject_id and T1.visit=T2.visit; NOTE: SQL execution methods chosen are: sqxcrta sqxjhsh sqxsrc( WORK.SCORES(alias = T1) ) sqxsrc( WORK.SURGERY(alias = T2) ) 3

The message in the log indicates that hashing was used to join the two tables, which by no means is a poor way to combine information from two tables. However, we know both of the data sets involved in the query are in order by Subject_id and Visit because they generated that way (see Appendix 1). The query could be improved by specifying the SORTEDBY data set option for both data sets to employ a preferred join strategy (i.e. a merge join) given that no sorting is needed. /* Figure 4B - Query With the SORTEDBY Data Set Option */.. from Scores(sortedby=subject_id visit) T1, Deviation(sortedby=subject_id visit) T2.. /* sqxsort conspicuously absent from _method output */ NOTE: SQL execution methods chosen are: sqxcrta sqxjm sqxsrc( WORK.DEVIATION(alias = T2) ) sqxsrc( WORK.SCORES(alias = T1) ) WHERE The WHERE clause in PROC SQL is used to subset data and specify join conditions. The WHERE data set option can be applied to tables in the FROM statement to subset the data as it is brought into the query. Consider the query below in Figure 5A. The information from the Surgery data set is used to flag the visit when the surgery took place in the Scores data set for only those surgeries occurring prior to visit 16. /* Figure 5A - Query Without WHERE Data Set Option */ proc sql; create table scores_surglt16 as select T1.*, case when ILV2.Visit gt 0 then 'Y' end as Surgery_Flag from Scores T1 left join ( from Surgery where Visit lt 16) ILV2 * <-- in-line view ; on T1.subject_id=ILV2.subject_id and T1.visit=ILV2.visit; The query above creates an in-line view from the Surgery data set that excludes procedures occurring at or after visit 16 which is then left-joined to the Scores data set. Alternatively, filtering of the Surgery data set could be done with the WHERE data set option as the data was brought into the query, as demonstrated in Figure 5B. Though the two queries are functionally equivalent, it is left to the reader to determine which is easier to follow. /* Figure 5B - Query With WHERE Data Set Option */ proc sql; create table scores_surglt16_2 as select T1.*, case when T2.Visit gt 0 then 'Y' end as Surgery_Flag from Scores T1 left join Surgery(where=(visit lt 16)) T2 on T1.subject_id=T2.subject_id and T1.visit=T2.visit; 4

Another useful aspect of the WHERE data set option is the availability of the colon modifier in conjunction with the IN comparison operator to search for varying length text strings in the beginning of a character field. PROC SQL has available in the WHERE clause string comparison operators such as EQT and LET to mimic the operators =: and <=:, respectively, that are available in the DATA and other PROC steps. However, there is no counterpart to in: available in the WHERE clause of PROC SQL. Note how multiple comparisons using the LIKE operand in the first query can be replaced by making use of the in: comparison operator in the second query. /* Figure 6 - WHERE Data Set Option with Colon Modifier */ proc sql _method; /* Multiple text string search conditions */ create table ex6a(label="&label6a") as from scores where subject_id like '100-%' or subject_id like '20%'; /* Using colon modifier with IN operator */ create table ex6b(label="&label6b") as from scores(where=(subject_id in: ('100-','20'))); RENAME Lund [2005] points out an example of when using the RENAME data set option is useful. Consider the query below where the Surgery data set is filtered on the case field. /* Figure 7 - RENAME Data Set Option in the FROM Statement */ proc sql _method; /* This query results in a error */ create table rename_case as from Surgery where case lt 4; * <-- Don t you use CASE to create fields in the SELECT statement? ; /* This query is valid */ create table rename_case2 as from Surgery(rename=(case=case_id)) where case_id lt 4; The first query in Figure 7 will result in error due to referencing the variable case in the WHERE clause. Confusion is brought on because CASE is a statement keyword used to create variables in the SELECT statement. The second query uses the RENAME data set option to change the name of case to case_id as the table is brought into the query to avoid the problem. A keen reader (that s you!) probably has already determined that this problem could have also been avoided by using the WHERE data set option. Other names of fields that can cause similar problems using SAS V8 and V9 are CALCULATED, EXISTS and TRANSLATE, as well as SUBSTRING in V8. Another potentially useful application of the RENAME data set option is when there are multiple key fields in two or more data sets that are being joined. Rather than specifying the join condition for all of the key fields, a natural join could be used. This coding short-cut will look for the fields with common names and types and use them to join the data sets without the user having to explicitly specify the equality conditions. So if the key fields in the data sets do not have the same name, the RENAME data set option can be used to change one or more of the fields in order to employ a natural join. 5

LIMITATIONS There are some limitations to using data set options with PROC SQL, which include the following: With the exception of READ, WRITE, ALTER and PW, data set options are not valid when specified for SQL created views in the FROM statement of queries. You will receive an error message in the log if you try to employ them. However, data set options are valid in the FROM statement for views created with a DATA step. Using data set options in the CREATE VIEW statement of PROC SQL will generate a warning indicating that they will be ignored, except for READ, WRTE, ALTER, PW and LABEL. Data set options are not valid syntax when querying a non-sas relational database such as ORACLE and DB2 with the PROC SQL Pass-Through facility. They are valid when querying non-sas relational databases when the connection to the tables is established with a LIBNAME. The data set options POINT and IN are not valid in the FROM statement. The data set options COMPRESS, INDEX and LABEL are ignored in the FROM statement, just as they are in the SET and MERGE statements of the DATA step. Data set options not are valid in the FROM statement of queries against the SAS (metadata) DICTIONARY tables. CONCLUSION This paper has demonstrated how the following data set options can be effectively employed in PROC SQL: DROP and KEEP Used in the FROM and CREATE TABLE statements in conjunction the * wildcard to selectively include/exclude fields in the output destination while noting the availability of the list range, name range and column modifier coding short-cuts to aid in this process. LABEL Adding a descriptive label to data sets in the CREATE TABLE and CREATE VIEW statement is a good programming practice. SORTEDBY Indicating to the SQL query optimizer that data sets are in order when this information is not captured in the metadata can direct it to using a more efficient join strategy and/or avoid superfluous sorting. WHERE Can be used as an alternative to the more verbose in-line view and allows in: as a valid logical operator. RENAME Changing the name of variables in the FROM statement may be necessary when fields have an alternative meaning, such as CASE and CALCULATED. It can also be used to change the names of key variables in data sets in order to make use of a natural join to combine tables. Balancing clarity, brevity, descriptiveness and efficiency in generating code is a key goal for which all SAS programmers should aim. For those who use PROC SQL, as well as the DATA and other PROC steps, making good use of data set options can help achieve this goal. 6

References Delwiche, L.D. and S.J. Slaughter, The Little SAS Book: A Primer 2 nd Edition, SAS Institute Inc., Cary, NC 1997 Dorfman, Paul M. and Gregory Snell (2003), Hashing: Generations, Proceedings of the 28 th Annual SAS Users Group International, USA --- and Koen Vyeverman (2004), Hash Component Objects: Dynamic Data Storage and Table Look-Up, Proceedings of the 29 th Annual SAS Users Group International Johnson, Jim (2005), The Use and Abuse of the Program Data Vector (The Procs), PharmaSUG 05 Kent, Paul, Inside the PROC SQL Query Optimizer, TS-320, SAS Institute, Inc., Cary, NC Lavery, Russell (2004), The SQL Optimizer Project: _Method and _Tree in V9.1. Proceedings of the Seventeenth Annual Northeast SAS Users Group Conference, USA. Lund, Pete (2005), An Introduction to SQL in SAS, Proceedings of the 30 th Annual SAS Users Group International Murphy, William C. (2004), Colonoscopy for the SAS Programmer, Proceedings of the 29 th Annual SAS Users Group International SAS V9 On-Line Document Acknowledgements The author would like to thank Jenni Borowiak and Melissa Yott for their helpful comments in reviewing this paper. 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: Kenneth W. Borowiak Howard M. Proskin & Associates, Inc. 300 Red Creek Drive, Suite 220 Rochester, NY 14623 E-mail: kborowiak@hmproskin.com Jsquare94@aol.com 7

Appendix 1 Code to generate sample data sets data Tx(label='Treatment Code Information'); do a=1 to 3000; Subject_No=a; if a le 1500 then Center=100; else Center=200; random_date=int(15000+20*ranuni(315975)); format random_date mmddyy10.; if ranuni(97511) lt.5 then tx=1; else tx=2; drop a; output; label tx='treatment Code' random_date='randomization Date' subject_no="subject Number"; run; /* Tx data set has 3000 observations */ data Scores(label='Recorded Scores at Visits'); length Subject_ID $8 Visit 8; array A[10]; array B[10]; do c=1 to 3000; if c le 1500 then subject_id=compress('100-' put(c,z4.)); else subject_id=compress('200-' put(c, z4.)); do Visit=1 to 20; do j=1 to 10; a[j]=j*ranuni(j); b[j]=.5+j**2*ranuni(j); drop j; output; drop c; run; /* Scores data set has 60000 observations */ 8

Appendix 1 Code to generate sample data sets (continued) data Surgery; length Subject_ID $8 Visit 8 case 8; do k=5 to 3000 by 197; if k lt 1500 then subject_id=compress('100-' put(k,z4.)); else subject_id=compress('200-' put(k, z4.)); run; Visit=10+int(10*ranuni(971156)); case+1; drop k; output; /* Surgery data set has 16 observations */ 9