Old Wine, New Wineskins: Why the SQL Procedure WIll Change the Way You Think Peter Kretzman, McCaw Cellular Communications, Inc. PernaPI' more tIlon w~h any of the other mkU-languages within the SAS System.. reasons abound to take a solid look at what PAoe saL con do fer you. FIrst, unlike til. oth .... (with Ihe _tion of the macro faolllji). PROC SOL is included with the base SAS Syat.... and Is tIlus available 10 all SAS u..... on aU platlonns as of Release 6.06. And. of course, the reason it is included with the base product is tIlaL like tile macro tacility and ABSTRACT Release 6.06 of the SAS system is NOT Just a "eN release. instead, in the increasingly diverse wood of -software developmenl "sin~ th. SAS Sysl.... Rei ..... 6.00 dramatically ups the ante. by prm'Iding dIff.....t 'and often bell.,.) mechantsms to achieve the same results as some common SAS unlike a specialized subsY$tem such as SAS/lML, ft is a general· purpose tool,' ooe which can be- used to advantage by f,Nf!fY $AS programner, tools such as the MERGE statement The Sal p",codu",. even 0!'-09 JUGt Q" ordlnruy SAS data sets, Is one of the most e.KdUng new features of Release 6.06. Especially consld ....d In tandem with the new obAIly to Index SAS data sets. PAOe sal immediately jumps Into the category of Mondal",,! Thin9" 10 Know for Ihe advanced SAS Secondly. PAOe sal. by .... hodying the "",...ging Structured Query l.S:nguage standard, represents a G1anCWdiZed way to fennuiate • query on (in other word•• to retrieve data from) existlng data. Given the BvalJabAity .of within the SAS System, programmers can now migrate qulckly from any of the numerous database management packages that Qlso employ the SOL standard as a query language, Although each of these packages contains extensions to- the SQL standard (and the SAS System is no exception). there is at least a common ground now among them. Most importantly. tne availab~ity of saL in ~I these packages means that thefr metaphor of data representation is common across them: a relational design, featuring table. w~h rows and columns. Aside from the us. of SQl within the SAS System itself. this commona.1ity rnearu;; it Is lConslderably -easier to conceptualize, and to code, access to data sacss database platfonns. using the SASJACCESS tools. Since the SAS Syslein can ship SOL queries d~ectly to external DBMS packages, it_ r-equlres no break in stride for the progJ1m1met to code a piel:O~ of SQl for intemal $AS System use, oomOO1ed in the same routines as sal code that is Intended to be shipped elsewhere at runtime, sal programmer. This advanced tutorial compares and contrasts some standard SAS toots (most notabty, MERGE) with equivalent ways to achieve the sam. effects using PRoe SaL Astounding Improvements ... perfonnance can often be achieved by using PROO sal instead of more traditional SAS tools. Concrete examples are provided, along with discussion of efficiency considerations. After this tutorial. your way of thinking about a SAS solution to a data combination problem wi. simply not be the same. This Morial is intended primarily for _tiVeI)I """erlenced SAS propmmers who are Interested In the latest tools and techniques for improving their productivtty, No previous knowledge of SOL is • .,,"oned. The argumen1fcr using ?ROC SOl1hat will doubUessly have the greatest weight with current SAS System users. however, is INTRODUCTION pme and simple efficiency, PF\OC SOL provides, at the very least. an aHemative (and more efficl-ent) way of achieving the results of one of the most convnon tools In the -SAS- System: a Over the years, numerous "'minl--languages" have been added or grafted On to the basic $AS System: the macro language, Saeen Control Language (SCI.). the Interaclive Mollix Language (IMI.). and. most recenHy. the Strucillred OueryLanguage (SOL). Each of these mlnHanguages exls.ts for a te6s0,.: each. unfortunately, has lis awn rules. syntax. and set of "gotchas for the h~ess SAS programmer. The sheer number of these addltfonaf Pmlnl-languagos" makea It fairly difficult for anyone anymore simply to daJm that they "know" SAS; instead. one "knows" the base SAS product, or "knows" each of these subsystems or subl81lguages indMdually. Few people (myself included) know aI of the mini-languages now available under the SAS Syslem. slmpl. malch-m...go, In many circumstances. PRoe Sal Can prOvide data combination results-that would be extremely difficuft to obtain lIslng conventional SAS System tools. This introductory pap« is designed to pique your inte.-est, to whet your appetite. and to make you reaUze the kinds of situations where you might use FROe saL to great advantage. n is NOT intended 10 be a thorough investigation into the vast array of data comblnatlon possib~Wes using sal constructs. The excellent SAS Guide :to the SOL P«icedure provides nunteroueJ fine ~ple8 and merits close study. SOL,./I "'whQle new ball game" within the SAS System, Will demand a significant efort if you wish to attain we fluency: however, It 15 the goal of thJs paper to pro\llde a qUicl< "CLJIto Ihe chase" ono show you the 80% benefit that can be obtained by only 21)% of the work. U Given the number of these minHtl"nguages. the burden of proof for learning any off them has essentiaiy been thrown on the SAS Sysl.... Itself. Users hove the righl (and the need) to ask: what.., thE;! tangibl'" benefits of leaming a particular 'subsystem? What can I do using this subsystem thot will vastly Increase my productive use ofthe SAS System overaD? Those Issues are the chief thing to consider w~h "'speet to the "leal kid on Ih. bloc1<, PRoesaL. SQl SYNTAX: THE BASICS The style of this paper will b~ to reveal Sal constFlJm 'lncremen1ally, rather than attempUo show them all at once in a kind of catalog. fOtmat. However, a basic temp1ate of a bjoin," or whQt SAS uset'$ refer to as a match-merge,1I is a iJseful startin-g point for most of the examples in this paper. H 271 0' fROM p<Xlion the SELECT clause. you wi~ get a sepsral. column lor esch 01 tho.. variables. labeled iden6ca1y. SAS l)Utput data. 'Sets, of eourse, can CQrmm only roe appes,ranC$ of any given variable). PROC SQL FEEDBACK NOPRINT; CREATE TABLE newtable AS SELECT ~ FROM data.master AS m# data. lookup AS 1 WHERE m.key = l.key M... the variable list is specified. Ihe 1<oyw0l'd fROM appears. lallowed by a lisl of one or more data sol names. separated by commas. Each of these data sets may be assigned an arbitrary alias by uSlrlg the keyword AS. followed by Ihe desired In our example, we have asSigned single letter aiases to each of the two data ..... Asslgnmenl 01 aliases is typically done so ttlat column names th~ match in the two data sets may be "qualified," (!hat is, slated unambiguously) during opsatIons such as processmg of the 'WI-EfI:E clause. ar,... ORDER BY idnumber; The above SQl code is a basic oonstruct that shows how to combine. 10' a la'll" labia (-.11IIISIer) wHh a smaller lookup !able (dataJookup). using the equivalent ofa BY variable. i1 this case named key. The equivalent conyentional BAS code would look as follows: _Ie. The Tricky Part Now .here is the 1rIoIIy pari. logically speaking (and " is nmember lhat this does NOT happ<on physically). the SOL procedure builds. lable lhal combines each row from Ihe first lable wHh every row from the second lable. In short, H nothing further were specified in the query, your rasun would be fNffI'I possilia oombinaJio.n of the rows. This HaJ combina.1ion" ~ortanllo DATA newtable; MERGE data.maater(in=m) data.lookup(in=l); BY key; result is What is referred to as the Cartesian product of the two IF m AND 1; tables. If your first table nas eight rows -and your second table has Ih"'" rows. the Cartesian produOi would conlairl 24 1OW1>: the first row of the fil"3t table combined. in tum. with .the 1Irst. second, then third rows of the second tabla, then the second row of the first 1abIe combined with .... e first. second, then third rows of th e secon.d table, and $0 01). RUN; Wt'$ go through the Sal construct. now and discuss its implcalions. Fim. Ih. procedure is Irlv01<od wHh • simple PROC sal cal: think of this as the gateway into the mini-language. It rums rohtrol tNt!:( to the sal processor, away frotn the conventional SAS DATA slep and PROC compiler. Saoomly. is a query language. intended at leaSt. oatensibly to provide printed ""uMo from eson query. ·It IUm" 0"" of OOU""" Ih.t much of U!e time you will want to use saL just for its combinatorial capabiRtie~. rather than to obtain a printed list Clf its resuits (lhls Is espeolal!y true When you are. combining lhoosands or mHlons 01 observations!) Hence, more often than no~ I find mysell using Ihe NOPRINT oplion to tum off the printing·of the resuHs. In the above exemple. the FEEDBACK option is also used. ThIs provides extra Information at runtime, in the SAS log. poJ1alning to how the ",ery was refonnulated by the sal ",ery optimiz.... and 11Irld H us""'llei ••,,,.lne. It's actually fairty seldom, of course. 1hat you really want, the cartesian product of any two lables. The whole concept of a match-merge, for -example. is bum upon the word Nmalch." That means you only cafe about CBSes where the key variable agrees SOL Note, in the two tables you are joining. What this means In Cartesian product terms is thai you only want to ·keep tho rows (in thai product) where the key ntiable ~n this case; .the variable named key) malohes. This match is spedlied In the WHERE clause the SOL query; ou, example 'ealUres Ihe equivalent of Ihe match· 0' merge, known as an liequijoin'" ail-ce the 'key variab1es must be equal the row 10 be kepI In the outputlable. '0' Typicaly. you -",oily"' Ihe. ,eferences to Ihe ·key variable by Ihe alas for one table. -8(J.1ating it to the qualified name of the key variableforlheothertabill. Typically, there are (N-1) c:onc:fltJ~s in Ihe WHERE clause for N lables being joined l<Igether. Since we are logically proceeding from a .labIo (the cartesian product. that Is) that fealures every possible comblnalion of rows. not necessary (unike wHh • match-merge) Ihat Ihe two inpul tables data.masIer and daIa.lookUp be soned on the I<ey variable. Noto. however. that the use 01 penods In Ihe WHERE clause Is ."eoilic to the SOL procedUre. and represenl$ use 01 Ihe n 1he above SQL code. that the syntax is quite -different n,. from oonventional SAS System syntax. Most, notabty. only one semi-<:<>on I, conlairled In the ",ery. 01 the very end lIsIs of thngs (variables, data sets, etc., have conuna~ sepBlBting the thing.: in the above _ I e , c"""",," separate Ihe names of the two data sets that will be lolned.· Finally. aHhough the two data.e18 Ispeoilled above oonlain penods In th"" names COl the conventionallonn of ·dbref.dsname:o. the periods In Iho WHERE clause are something else ildeed, and are discussed further nalasing" exp~lned above. finQlIy. iSlnce the input tables are not necessarily SQrted, the results of the query are not in any particular guaranteed order. For that reason, you may specif{ an ORDfR BY ,clause to the query, which serves to place them In the order you desire. Note thai the variable spedlied in Ihe ORDER BY clause does ",,/ hQ\te to be tha same variable- Q" which the equijoin was performed. In genenil. PROC Sal gives you • great deal aI freedom in variable selection: variables listed In your WHERE dause. for example, do not need to be in the variable fist that appears Immediately sfterlhe SELECT _emen!. below. Ignore the CREATE TABLE statement IQ( now. The meat of most SQL code is one or more SELECT clauses. A SELECT clause has two parts, one where you specify what columns you want and the second wh ..... you specily what data .01> wIM be used. In the above example, we have specified an asterisk for a variable list, meaning that we want All variables from each of the data sets. (NOTE: PROCSOllalres Ihatqun.~ ffyou ore obtsIning printed ou1p"" 10, and a variable o'the same name appears in more than one of -the data sets named In the _Ie. 272 Piquing Your Interest PROC SQL NOPRINT, CREATE TABLE SELECT ~ NQW that we hav-e g-ottfilO t:h~gh the rudiments of the syntax Involved in an, equljoin, ,let's look at some timilgs and oomparison-s, stacking up & conven1lon~ match-merge against Ihe equivalent SOL construct. Keep in mind that this is, only an example, and Is not inlended by any means 10 show that SOL is always beller than a conventional match"""'l!". Oepanding on your situallon, actual n~ and results may vary ronsidetably. All Ilmings shown are from runrnng the code on a N-orthgate 486/25 PC, uslng,lhe SAS System under 08/2 (beta lest verslon). Am. here Is the atandard match.... erg.. FROM _ carefully. AS a, QUIT, 11m.: 3 minutes, 24.44 uconds (1,173 obs. extracted). In this cas•• RAWOI Is Whaaaat? This I. the exact ••me rodel Wh .... did .. our time savlngs g01 In fact. this resuH Is now considerably glNter use of CPU time than our match merge of one. minute, 44 seconds. Well. n tum. out th.t Ihis most recenl """"",10 represent. Ih. same job run without an ,Index having been crealed on the master dBIB. set: 'lin this case, ra'W'01). The Index, then, allows 1he SOL query optimizer 10 be con.hlerably more intelligent about how n processes the query. WIthout that Index. " simply has 10 sort both Inpul dsta oeI$ (thIs h_ens behind the soen.., at great cost il both CPU time and in disk resources} and proceed to slog through the dat!>. Please observe the recorded run ' DATA MONTH1; ~RGE rawOl AS interest AS w WHERE a.symbol=Wosymbol a dsta set containing appro>dmalely 101,000 ob_ons. INTERESr is a dsla set oontalning approximately 55 occurrences at the key variable SYMBOL. result~ RAW01{in~~aw) INTEREST(in=wanted); BY SYMBOL; So no problem, right? Just create 81'1 ildex on all yoor data and you" be In g,eat shape, right? Wrong. Here', Ihe malch....erge example, the one that ran in ana mlnute, 44 seconds In our previous result IF RAW AND WANTED; RUN; Tme: 1 minute, 44.92seoonds (1.173 obs. mraoted) DATA MONTHl; HERGE RAW01{in-raw) INTEREST(in=wanted); Hmmm. Not bad for a Fe: processing over 100,000 observations in only 105 seconds. Now lei'. by H with PROC SQl: BY SYMBOL; IF RAW AND WANTED; PROC SQL NOPRINT; CREATE 'TABLE resultl AS SELECT • FROM raw01 WHERE a.symbol~.symbol 11me: 1 minute, 3 • ..,ond. (1,173 ob •. extracted) AS a, interest AS w Here we go again. Th~ time, the code ran In only 63 seconds, not 106, So theiast 11m. was w~houl an Index. right? Wrong: in QUIT; , fad. just the -opposite. In a conventional match-merge where the dala ;s already sorted, Ihe presence of an index "'*'aJtf slows ~ down. The reason for this is thaI Ihe DATA Slep processor is not nearly as intel~geJ1t as the SOL query optimizer. It simply nas to go through each and every observation ~ the iarlle data set (raW01) and can only check " _ ft ha. perfomled the combination with Ihe interest data set (via Ih. . sUbsetting IF statement). If an index is present. it goes out and Hmmm. Hnvnm. e seconds compared to 105. How would you feel .bout driving a thai got you 200 mil... to the gallon? JU. co, lessl oslenslbly, H appears lhal PROC SOL, In this instance, can give . you an order of magnitude better performan~e uses over a it. but slnce H.has 10 go through al the data In the large d .... set anyway. ~ do..", help. In fact. ~ hinders. enough so thai a 63 second job becomes 67% longer as a result. . standard match-merge. Not so fast, buster Creating an Index But let's slow down a bit and run a few mere t~ before we get Now that you've seen the potential benefits of. indexes. howerter. it would be helpful 1-0' know how 10 create them.. There ate two ways. to a-eate an index in the SAS System: use -moc DATASETS or use PROC SQl ttsell, toe exci1ed. Here's a couple mere examples with slightly different resuhs: 273 PROC D~T~SETS mighty __ In shOO. the downoide Is that every tim. you went the data In qu..tion. th~ SAS System has to go out and construct H. But there ate many advantag.. to keeping the views klstMd of many s u _ or aitema1lv. versions 01 data. U..... may want s..ersI different version. (literally, views) of the data, and keeping several physical sets of data kI synchronlzaUon Is notorioustv <ifficuft. With a view, the data are always current since data are obtained from a single source and manlpulnted Intn relevant loons. Andy, views can shield yow u ..... from the messy datals Involved in large end complex LIB-WORK; MODIFY MWOl; INDEX CREATE SYMBOL, RUN; PROC SQL; CREATE INDEX (SYMBOL) ON MWOl(SYHBOL); QUIT; merges. To the user, they may not even be aware that a ~en ·data set" Is reaJy • recipe and not a cake aI aI. Once the view Is coded. you can bo certain that aI of lis users ... be per10nning the merge corredly. sn"" h Is bolng <lone for them; RUN; _0 TIme: 4 minutes. 3.69 seconds be sure that the users are geWng the most recent you can form of your pr1maIy dsta. And, of course •• you want 10 ohange where and how you have inlptemOl1ted the physical fonn of your data 'oaae, • Is a good deel eaol... to change a view (whloh Is, after all, the publio view 01 tho data) than 10 change the data TImings and PiHalls Here's- a summary of U1e timings and the pitfals, in chart form: Operation Indexed Non-indexed MERGE saL au,"" 1:45 1:03 3:24 0:08 structures themsefves. Invisible Martar SOL VIeWS, in other words, are a way of providlng USefS with ·invlsible mortar," by which bricks are slapped together and passed on together. 1ianSparently to U1e view~s user. See my SUGI 15 pap ... (Kretzman, 1990) on the "Mortar and Bricks" theme ;, genersl. Again. !I: is hard to provide hard-and-fast rules of thumb now ,that the SAS System is so complex (with indexes. multiple platfonns, etc.). but/or the oImpie kinds 01 equljolns I have outlined here. H $eat'I1S usually advantageous to use PROC sal and combine it "With the use of an Index. "that same Indexed data set is going lot's look at. typical view constructed with PROC saL As with our other examples, it represents: the equivalent of « match- merge. to be used in conventional DATA -steps, however, you may wish to detele the index. In future SAS releases, there may be a way to lns'buct the SAS System not to use an Index In a particufar step. but the", is currenUy no such method avMable. PROC SQL NOPRINT; CREATE VIEW thismon AS Remember .s well that 1il8r<O Is • considerable cost. depending on the nature af the data. 10 cresting an Index In the first place. This root muot be weighed agaklat how often (and how) the data in. question are goilg tD be used. SELECT a.symbol, date, high, low, close, volume F,ROM rawOl· AS a, interest AS W WHERE a.symbol=w.symbol QUIT; Why Use SQL Views? M.mng rNay now from the topic of pure efficiency. the rest of this pap... wia desl with IUlOth ... maiO!' reason I<> u"" SaL: the &bHHy to creste SOL Views. You will note that this is virtually the exact same code as I gave In the tining examples eadier;, this pap .... The key difference, however, Is lhat CREATE VIEW Is being used, rather than CREATE TABLE. In short, I'm 1..lng PROC SaL to b"Ud and file a recipe h ..... not to construct the actuol cake. The recipe, in this instance, will be a "'work (not pennanent) view called The SAS System. compOr<Od to most thlrd-generellon languages. has always had 8 weak point In Us lack of &biHy to "bottle,' as I Ike to put H. Other then with tho macro language. there haven' been many constructs in the SAS System 10< Geslgning something once, then using that something as a buldng block lor othe< purpo.... Most languages have procedures; lho SAS System does not. at least within lis own framowori<. SOL now provi_ SOL views, which are a kind of "botHilg" tool, not fOf user--wrilten procedures per se. but for N 1hIomon. "ser_ let's now examine « case where we use this "View to -do some work. Note how the reference to thismon appears in a place where an ordinary data sot relerence could appear. This exampte also happens I<> be using more SQl. bul ~ wouldn~ have to be. The key point about views Is that they may be used anywhere you could refer to a SAS data sot (with the exception thai they may not b. to In the current release of the SAS System). desigr'lill9 IIrl1cipes. 1I Rather than aloMg a particular version of the data, it is now possible to store Us -recipe, so 10 speak, or how 1hat version may be constructed. AI the trne you need tbat v .... lon of the data. you may . . - to ft as H ft actuaUy exist.. employing Its name In SAS prooedures and so on, AI runtime. the SAS System wil go out. proces. tho recipo. and feed the resulting r;ake to the procedures that ate referring to ft II _en The polnl of this particular query. _ from Its use of an sal view. is to obtain • set of stock symbols, ordered by desceodng average cIosi1g price In the current month. The purpose of the em. OJ co""'''' there are pros _ to having a recipe, especially at Ones when you reaJy want the cake and you w""t the cake 274 view is to obtain only those stocks that ore of interest. as contained in a SAS data set of l<ey symbols. changed to AVa, _ l e a were qualified in "'IIKY Instance, and soon. The resuKs, as printed, 01 this query look lire Ihe lalowing: PROC SQL FEEDBACK; SELECT symbol, mean(close) AS avgclose format~7 .2 FROM thismon GROUP BY symbol ORDER BY avgclose DESC SYMBOL ERICY IBM HOT KSFT GE AVGCLOSE 196.16 105.59 62.13 59.40 58.07 QUIT; Additional Complexities FlIsI, before we dI"""$o tha role of view. in ",solving this query, let's examine the addiliaMI sal leature. thst emerge in this code. An>!, note thst we have specified neither CREATE TABLE or CREATE VIEW. That m<llllls thal ou, output will be printed only. Secondly, we have instructed PRae sal to compute a new variable, which we have told It to call BVgclase." the value of which wll be the mean of the variable called close. The AJ;, the reader has no doubt surmised by now, the compleldty in the SOL procedure far exceeds the swpe of this one paper. Topics of interest that I have not covered include the following: GROUP BY clause tells PAOe SOL over what groups the mean will be osIoulated (In ohol1. wa W80t one moen for each value 01 Ihe variable symbo~. Finally, we would like our results sorted in descending order of Iho newly computed varlalole. o o o Complexions: outer joins, retlexivejolns, etc. Subquerio. (within WHERE claus•• , etc.) Updating data sets using sal o o Set operators (UNION, EXCCPT. INTERSECTION, etc.) Querying I1lI.Iltipie tables Oth... arlthmoUc expresslonsln Ihe SELECT c1auso o lmagine dOing this same operation using conventional SAS codel You would need a PROC SUMMARY, then a PROe SORT, then a PROe PRINT. Sal combine. iii 01 those Ihings CONCLUSION Into one. The SQL Procedure can and should be a vital tool in the arsenal Note once again that there are syntacticat anomalies to watch out for. The "DESCH option on the ORDER BY clause, for example. appears sflor the name of the variable to which it app~es. of the accomplished SAS proQrammer. For pertormance reasons alone on basic constructs, h is worth taking the time to learn and 10 learn welt. unlike how it appears on an ordinary SAS BY :statement aIs also abbreviated diflerenUy. Comments, suggestions, and ques1ions are welcome. author may be reached at the foDowing address: The fEEDBACK option on the PROC sal statement Hoelf insllUCIs Ihe PROe sal processor to show us how ~ is expanding Ihe qJery. In short how H is resolving the ,,,,,!pe that n has stored in the sal view. Here Is the resuft of that The Peter KreIzman McCaw Celular Communications, Inc. P.O. Box!l6065 Kiricland. WA 981l3:!-9765 Voice: (200)8211-1344 FAX: (200)828·1300 resolution: SELECT raw. Symbol, AVG(raw.close) AS avgclose In addition, the author may be contacted via Internet, USing the address: FORMAT=7.2 kretzman@Uwavm.acs.washlngton.edu. FROM (SELECT raw. symbol, raw.date, raw. high, raw~cloae FIlOM WORK.RAWOl WORK. INTEREST WHERE RAW, WANTED ACKNOWLEDGEMENTS The author wishes to Ihank Ihe felowing people for their contrlJuUons (wittingly or not) to the thought !hal went into this peper. Tm F""'ham, Patricia GeroI1d, Gene Hal1. and Paul Kent. In addition, numerous ideas were obtained from the SAS-L oon......ce on BITNET. raw. symbol=wanted. symbol) GROUP BY raw. symbol ORDER SY avgclose DEse; Note how the reference ., the code to thismoo has been resolved to anoIhBr SELECT clause, one wmch was obtained from the "recipe" specified In Ihe view. The Sal prooesoo, hao done scene other "cosmetic- ltIings: nc1e that MEAN was BIBUOGRAPHY I. Dale, C.J., An In~n 10 DaIabase ~ FIiIh Ecli60n, New York, NY: Addison-Wesey.lnc .. 19!1O. 275 2. Johnson, James R., snd Comejo, Roger D., "Interlacing Nonnalized Relational Database Struolures with SAS SoIIware," PR>CHd1ngs 0/ the FifINrrIh Anoos! SAS U-. GRlUpJllI>i>tmWonaIeon _ _ Cary. NC: SAS Instltulolnc.• 1990, pp. 421-427. 3. Johnston, Su51!ln E., "Using the SOL Ptoceoo.-e m SAS Pro~s," PR>CHd1ngs of It!e F/fieGnth Annual SAS Users Group , _ _ eon _ _ Cary, NC: SAS Ins_lno., 1000. pp. 3211-334. 4. Kre!zman, Peter, "Mortar and BricIai: Using Baslc SAS Sys\em Procedures to Manlpulate Your Data.· Proceedings of the rdlsen1h Annual SAS Users GRIUp I n _ ~ Cory. NC: SAS Insdlu!. Ino.. 1990. pp. 155-162. 5. SAS Institute, Inc., SAS GuIdIt II> IfHJ saL _ UHgS Md _ V~n II; FITOt Edl/ion, Gary. NC: SAS Institute, Inc., 1989. SAS,SI>S/ACCESS and SAS/lML are ~sterod tn>.demari<s 01 SAS Institute,lnc., Cary, NC. 276