2.4 SAS編程語言
前面幾個小節(jié)我們基本上都把SAS當作一個軟件來進行介紹,輔助性地展示了一些SAS代碼,對于初學者,如果沒看懂前面的代碼沒有關(guān)系,理解軟件層面的概念即可。從這一節(jié)開始,我們一起捋一捋SAS作為一門編程語言的基本概念和基礎(chǔ)知識。
→2.4.1 SAS程序結(jié)構(gòu)
SAS程序是由一系列SAS語句(statement)組成,所謂SAS語句通常是指以SAS關(guān)鍵字(keyword)開頭,始終以分號(;)結(jié)束的代碼行。最常見的SAS關(guān)鍵字就是「DATA」和「PROC」,因此最常見的語句就是DATA語句和PROC語句。當然,SAS的關(guān)鍵字多如牛毛,我們也不必刻意去死記硬背每一個SAS關(guān)鍵字。在DMS、EG和SAS Studio的編輯器中,SAS都會自動給關(guān)鍵字著成深藍或者藍色,EG和SAS Studio還會給出提示,初學者可以嘗試看看。
另外,如果從程序塊上來講解,SAS程序可以分為兩大塊:DATA步和PROC步。所謂一個「步」(step)是指這樣的一個程序塊。
● 以DATA語句或者PROC語句開頭。
● 以RUN語句(大多數(shù)情況下)、QUIT語句(部分情況下)、新的DATA語句或者PROC語句結(jié)束。
在SAS編輯器中,SAS會自動顯示橫線以隔開DATA步或者PROC步(見圖2-10)。需要留意的是,有些語句只能在DATA步里出現(xiàn)(如INPUT語句),有些語句只能在PROC步里出現(xiàn)(如CLASS語句),有些語句DATA步、PROC步都可以出現(xiàn)(如FORMAT語句),而還有些語句可以既不在DATA步也不在PROC步出現(xiàn),它們可以單獨出現(xiàn)(如前面使用過的LIBNAME語句),此即DATA步語句、PROC步語句及全局語句的概念。

圖2-10 DATA步與PROC步
SAS程序除了單獨的DATA步和PROC步程序,還有可以把它們打包組合在一起的程序,那就是宏程序,宏程序本質(zhì)上是文本替代,用更少的文本替代更多的文本。這個話題暫且不做過多介紹,留在后面的第10章進行詳細說明。
→2.4.2 SAS語法規(guī)則
規(guī)則的SAS程序書寫風格看起來基本就是被DATA步和PROC步分割的條塊,其實SAS程序書寫的格式是比較自由的,如果要真正究其語法規(guī)則的話,有兩方面:①SAS語句語法規(guī)則;②SAS名語法規(guī)則。
SAS語句語法規(guī)則:
● 分隔單詞的可以是一個空格或特殊字符(比如加號、等號等運算符),也可以是多個。
● 程序可以在任何列開始,也可以在任何列結(jié)束。
● 單個語句可以寫在多行,多個語句也可以寫在一行。
SAS名是指SAS給其一些語言元素(如邏輯庫、數(shù)據(jù)集、變量以及格式等)的名稱標記。SAS名有兩類。
(1)SAS系統(tǒng)定義名,如自帶的庫名WORK、SASHELP等;如特殊的數(shù)據(jù)集名_NULL_(不創(chuàng)建數(shù)據(jù)集)、_DATA_(自動數(shù)據(jù)集名)、_LAST_(最后一個活動數(shù)據(jù)集);如SAS DATA步的自動變量名_N_(觀測號)、_ERROR_(錯誤標識變量);如特殊的變量列表名_CHARACTER_(所有字符型變量)、_NUMERIC_(所有數(shù)字型變量)、_ALL_(所有變量);以及SYS開頭的宏變量名如SYSDATE(日期)、SYSVER(SAS版本)等。
(2)用戶自定義名,自定義名不能與系統(tǒng)定義名相沖突,且需符合SAS命名的語法規(guī)則,總結(jié)起來可歸納為以下三點。
● 只能由數(shù)字、字母、下劃線組成。
● 首字符不能是數(shù)字。
● 長度限制各有不同,有的最長可以達32個字符(如變量名,宏變量名),有的最長只能有8個字符(如邏輯庫、文件引用名以及引擎名)。
這個命名規(guī)則一定要遵守嗎?是的,都應(yīng)該遵守。這個規(guī)則能打破嗎?可以,但不推薦。不過,有的時候,我們也確實有特殊需求:比如如何打破規(guī)則讓SAS也可以用中文命名數(shù)據(jù)集、命名變量呢?這時候,我們可以通過修改系統(tǒng)選項VALIDMEMNAME和VALIDVARNAME的值來實現(xiàn),如圖2-11所示。

圖2-11 SAS中文名數(shù)據(jù)集和變量名
程序2-6 SAS中文名數(shù)據(jù)集和變量名
*===中文名數(shù)據(jù)集; *===中文名變量; options validmemname=extend validvarname=any; data 中文名演示; SAS中文變量名="YES"; SAS中文變量名="YES"; '2SAS中文變量名'n="YES"; '2SAS中文變量名'n="YES"; 'SAS空 格變量名'n="YES"; 'SAS空# @ %格特殊字符變量名'n="YES"; run;
語法規(guī)則只是對編程的合法性給出了最低的要求。在合法性的基礎(chǔ)上,我們還應(yīng)追求語法風格的統(tǒng)一和規(guī)范,這樣不僅方便自己日后閱讀調(diào)試,也方便他人審閱,下面是同一段簡單的SAS程序,對比左右兩邊的風格,正常的人類都更愿意看左邊的,對吧?編程人士中有一個術(shù)語叫Good Programming Practice,GPP,即良好編程實踐,很多編程語言都有推薦的編程規(guī)范,遵循這些規(guī)范,可以極大地方便與同行的交流,筆者自己總結(jié)過一些SAS的編程規(guī)范,具體可參考附錄。
程序2-7 編程風格:規(guī)范與凌亂
*===自建永久庫; libname demo "D:\03 Writting\01 SAS編程演義\02 Data\Clean"; *===建永久數(shù)據(jù)集,demo.不可省略; datademo.class_datafile; set sashelp.class; run; *===建臨時數(shù)據(jù)集,work.可以省略; data class_datafile; set sashelp.class; run;
libname demo "D:\03 Writting\01 SAS編程演義\ 02 Data\Clean"; data demo.class_datafile; set sashelp.class; run; data class_datafile; set sashelp.class;run;
→2.4.3 SAS語言元素
作為一門編程語言,SAS語言元素除了上面提及的SAS語句(statements),還有表達式(expressions)、選項(options)、格式(format)、函數(shù)(function)以及Call列程(Call Rountine)等。
1. 表達式
表達式是SAS語言中一個非常重要的概念,SAS在生成一個新變量、給一個變量賦值、計算新值、變量轉(zhuǎn)換以及依據(jù)不同的條件進行處理都需要借助表達式來實現(xiàn)。什么是表達式? SAS官方給表達式的定義比較拗口:表達式是由一系列操作數(shù)和操作符構(gòu)成的、可執(zhí)行的、并且產(chǎn)生結(jié)果值的序列。簡單來說,表達式就是告訴SAS對什么對象執(zhí)行什么操作,從而得到一個結(jié)果的命令。被操作的對象叫操作數(shù)(operands),執(zhí)行操作用的符號就是操作符(operators),習慣上稱運算符的更多,執(zhí)行的結(jié)果可能是一個數(shù)字值,也可能是一個字符值,還可能是一個布爾值(是/否、真/假、1/0)。
(1)操作數(shù):操作數(shù)可以是常量、變量,也可以是表達式。常量,顧名思義,表示一個值是恒常固定的量;同理,變量表示值是可以變化的,有一套數(shù)值去刻畫某個特征的量。
常量有以下四種情況。
● 字符常量:字符常量由1~32767個字符組成,必需放在英文引號內(nèi),引號可以是單引號,也可以是雙引號。字符常量中包含單引號(雙引號)時,可以用雙引號(單引號),或者連續(xù)的單引號(雙引號),如:“Hongqiu Gu’s Book”。
● 數(shù)字常量:數(shù)字常量無須多言,只需留意除了標準計數(shù)法(如:1,-5,+49,1.23,01),科學計數(shù)法(如:2E23,0.5e-10)和十六制計數(shù)法(如:0C1X、9X)也可以。
● 日期時間常量:時間日期常量包括日期、時間、日期時間常量三種,命名是需要采用單引號或雙引號加D(日期)、T(時間)、DT(日期時間)后綴來分別表示,如'08Sep2016'D、'11:11'T、'08Sep201611:11'DT,具體可參考程序25 SAS日期、時間以及日期時間的本質(zhì),這種引號加字母后綴的命名方式稱之為名稱文字(Name Literal),在使用非規(guī)范的數(shù)據(jù)集名、變量名時也需要用到這種形式。
● 位測試常量:在引號里由0,1以及點(.)組成字符串,且后綴為B,如'..1.0000'b,用來測試對應(yīng)的位是否為0或1。這種常量使用較少,在此不做具體介紹。
變量有兩種類型:字符變量和數(shù)字變量。日期、時間以及日期時間在SAS里其實也是以數(shù)字存儲的數(shù)字變量。如前所述,日期變量的值為距離1960年1月1日的天數(shù),時間變量的值為距離凌晨的秒數(shù),日期時間的值為距離1960年1月1日凌晨的秒數(shù)。
程序2-8 SAS中的常量
*===常量; data_null_; *==字符常量; c1="Hongqiu Gu's Book"; c2='Hongqiu Gu''s Book'; c3='Hongqiu Gu"s Book'; c4="Hongqiu Gu""s Book"; *==數(shù)字常量; n1=123; n2=-123; n3=+123; n4=1.23; n5=0123; *===日期時間常量; d='08Sep2016'D; t='11:11'T; dt='08Sep2016:11:11'DT; *===在日志中輸出; put c1-c4 ; put n1-n5 ; put d yymmdd10.; put t time.; put dt datetime.; run;
(2)運算符:SAS運算符從位置上講,放在操作數(shù)前面的叫前綴運算符(如+、-),放在操作數(shù)中間的叫中綴運算符(大多數(shù)運算都是);從功能上講,有用于算術(shù)運算的算術(shù)運算符(如+、-、*、/),用于比較大小的比較運算符(如>、<、=、^=),用于邏輯運算的邏輯運算符(如^、&、|);算術(shù)運算符運算的結(jié)果通常為數(shù)值,比較和邏輯運算符運算的結(jié)果為真(1)或假(0)。關(guān)于這幾種運算符,沒有太多可說的,請參考下面的表2-2、表2-3及表2-4。
表2-2 算術(shù)運算符

注:乘法中,*號是必需的,2y或者2(y)都是非法的。
表2-3 比較運算符

注:EQ=EQual, NE=Not Equal, GT=Greater Than, GE=Greater than or Equal to, LE=Less than or Equal to, IN=In the list。
*NE的符號在不同的鍵盤上可能會有所不同。
**>=、<=與以前SAS版本兼容。WHERE或SQL語句中不支持。
表2-4 邏輯運算符

注:*不同的操作環(huán)境可能符號有所不同。
除此之外,還有取小運算符(><)、取大運算符(<>)以及連接運算符(||)。><和<>分別用來找到兩個操作數(shù)中的最小值、最大值,||用來連接前后兩字符。
如果只是單個運算符時,不會牽涉運算順序的問題,但是,當有多個運算符時,就需要厘清運算順序了,如復(fù)合表達式中會有多個運算符,其運算順序的原則是:
(1)先算括號中的表達式,再算括號外。
(2)不同組有不同的優(yōu)先級。
(3)同組內(nèi)有不同的運算順序。
具體示例詳見表2-5。
表2-5 復(fù)合表達式運算順序

2. 選項
SAS選項包括系統(tǒng)選項和數(shù)據(jù)集選項。系統(tǒng)選項主要是一些可以影響整個SAS程序執(zhí)行或SAS會話交互的指令,數(shù)據(jù)集選項是僅用于數(shù)據(jù)集的選項,如變量的重命名與篩選、觀測篩選、數(shù)據(jù)集權(quán)限控制等。
3. 格式
格式依據(jù)應(yīng)用場景,分為輸入格式和輸出格式;依據(jù)定義方式,分為系統(tǒng)格式和自定義格式。格式告訴SAS按一定的模式讀取、顯示數(shù)據(jù)。關(guān)于格式,詳見第7章。
4. 函數(shù)與CALL例程
SAS函數(shù)可以接收參數(shù),執(zhí)行一些運算和操作,然后返回一個值。CALL例程與SAS函數(shù)類似,不過不能用在賦值語句或表達式中。關(guān)于函數(shù)和CALL例程,詳細討論將在第6章進行。
我們通過一個綜合的例子來簡單感受上面提及的一些概念。
程序2-9 SAS語言元素演示

→2.4.4 三種邏輯結(jié)構(gòu)
就如人生中面臨的三種情境一樣:按照既定的步驟去做一些事情、依據(jù)不同情境選擇性地應(yīng)對一些事情、在某些情境下重復(fù)做相同的事情,幾乎所有的編程語言都設(shè)計了三種程序邏輯結(jié)構(gòu):順序、選擇和循環(huán)。
1.順序結(jié)構(gòu)(sequence)
順序結(jié)構(gòu)的程序執(zhí)行時就按照代碼出現(xiàn)的順序依次執(zhí)行:第一條語句,第二條語句,第三條語句……前面的所有SAS代碼幾乎都是順序結(jié)構(gòu)式的。
2.選擇結(jié)構(gòu)(selection)
最經(jīng)典的選擇結(jié)構(gòu)語句就是IF-ELSE/THEN語句,告訴SAS在滿足某條件的情況下執(zhí)行一套操作,不滿足則執(zhí)行另一套操作。例如,我們對SASHLEP庫CLASS數(shù)據(jù)集的人按男女性別的不同分別抓出來放到Male和Female數(shù)據(jù)集。
程序2-10 IF-ELSE/THEN示例
datamale female; set sashelp.class; if sex="M" then output male; else if sex="F" then output female; else put "Invalid sex :" sex ; run;
需要留意的是:
● 對于情境的分類,要考慮完全。因此,盡量最后加一個ELSE語句,納入其他所有可能情況。
● 如果某種情境下,希望執(zhí)行的不僅僅是一個動作,而是多個動作,此時可以在關(guān)鍵詞THEN后面用夾板語句DO-END,把多個動作整合在DO-END語句中。例如,我們嫌棄SEX不文雅,把它換成GENDER,用Male、Female標明男性、女性。
程序2-11 IF-ELSE配合DO-END
datamale female; set sashelp.class; if sex="M" then do; gender="Male "; output male; end; else if sex="F" then do; gender="Female"; output female; end; else put "Invalid sex :" sex ; run;
3. 循環(huán)結(jié)構(gòu)(iteration)
循環(huán)結(jié)構(gòu)的程序是只要滿足某個特定的條件,就重復(fù)進行某些操作。SAS里常見的循環(huán)語句有三種:DO循環(huán)語句、DO-WHILE語句以及DO-UNTIL語句。
(1)DO循環(huán)語句。DO循環(huán)語句其實就是DO-END語句的衍生,在DO后面添加循環(huán)的條件,這個條件可以是數(shù)字、字符、日期的列表;可以指定起始值和終止值以及步長;還可以是前面兩者的混合。
程序2-12 DO循環(huán)語句
dataschedule; do date='01Sep2016'dto '30Sep2016'd ;*日期循環(huán); day=weekday(date); if day in (1,7)then Activity="Running"; else if day in (2,4,6)then Activity="Writing"; else Activity="Reading"; output; end; run; datarandom; do i=1to 10; *數(shù)字10次循環(huán); r=rannor(23);*生成隨機數(shù); output; end; run;
(2)DO-WHILE語句。與DO循環(huán)語句每次按照指示變量的值去執(zhí)行不同,DO-WHILE語句會先判斷是否滿足條件,如果滿足則執(zhí)行否則跳出循環(huán)。
(3)DO-UNTIL語句。與DO-WHILE語句會先判斷是否滿足條件不同,DO-UNITL語句不管三七二十一,先執(zhí)行了本次循環(huán)再說,而后再判斷條件是否滿足。在做條件判斷時,DO-UNTIL與DO WHILE的思維也不一樣:DO-UNIL是如果不滿足,則繼續(xù)下一次循環(huán),如果滿足,則跳出循環(huán)。具體可留意程序2-13的條件差異。
程序2-13 循環(huán)語句DO WHILE與DO UNTIL
datadowhile; i=0; do while(i<5); i+1; output; end; run; datadountil; i=0; do until(i>=5); i+1; output; end; run;
如果讀了上面的文字和程序,對三種邏輯結(jié)構(gòu)還是不太清楚的話,圖2-12或許能讓我們的思維更清晰些。

圖2-12 程序的三種邏輯結(jié)構(gòu)
→2.4.5 數(shù)組結(jié)構(gòu)
SAS編程語言不像其他語言那樣有豐富的結(jié)構(gòu)體(struct),用來聚合數(shù)據(jù)類型,這正如SAS的數(shù)據(jù)類型只有簡單的字符和數(shù)字兩種。不過,其他編程語言的數(shù)組(array)的思想倒是在SAS編程語言中有充分的利用。
SAS編程語言里,數(shù)組是一系列有特定順序的變量組成的一個臨時變量組。之所以說是臨時的,是因為數(shù)組僅僅存在于DATA步執(zhí)行的過程中。數(shù)組中的變量必須有相同的數(shù)據(jù)類型,如果全為字符型,則為字符型數(shù)組;如果全為數(shù)字型,則為數(shù)字型數(shù)組。此外,如果數(shù)組里的值只在一個維度上排列,比如就一行,這就是一維數(shù)組;如果數(shù)組里的值在多個維度上排列,比如行列上都有,就像一張EXCEL表格,這便是二維數(shù)組。
在什么場合下會用到數(shù)組呢?怎樣理解一維和二維數(shù)組呢?舉例說明:比如某研究項目持續(xù)每天測量患者的收縮壓(SBP)、舒張壓(DBP),并持續(xù)了一周,這樣就有7次收縮壓和7次舒張壓的測量值。當然,我們可以把它們分別存儲在SBP1~SBP7、DBP1~DBP7這14個變量中。但是僅僅這樣,可能還不夠,如果后期我們發(fā)現(xiàn)這批血壓儀的測量值有系統(tǒng)偏差,SBP比正常測量值低5mmHg, DBP比正常測量值低3mmHg。現(xiàn)在要校正的這些血壓值,我們要分別對SBP、DBP寫7個賦值語句,總計14個。這樣是不是太煩瑣了?是的。這時候數(shù)組就可以派上用場了。
我們可以建兩個數(shù)組SBP、DBP分別用來存儲SBP1~SBP7、DBP1~DBP7。就像下面這樣有一排格子,每個格子有一個編號,SAS依據(jù)格子的編號進行數(shù)據(jù)的存取,這就是一維數(shù)組,數(shù)據(jù)排列就在一個維度上:行。

當然,我們甚至可以直接建一個數(shù)組,同時把7次SPB,DBP的值打包在一起,這就是二維數(shù)組,數(shù)據(jù)排列在兩個維度上:行和列。

上面只是給出了數(shù)組的概念示意圖。實際操作時涉及兩個核心問題:一是如何定義數(shù)組;二是如何訪問數(shù)組。
1.定義數(shù)組
SAS DATA步中,我們通過語句ARRAY來定義數(shù)組。其具體語法格式請參考語法2-1:

語法2-1 定義數(shù)組語句ARRAY語法參考卡片
關(guān)于數(shù)組語法的一些解釋如下所述。
● 元素個數(shù)可以用{*}代替,表示讓SAS自動計數(shù),也可以指定具體的數(shù)字,如{7},還可以指定一定的數(shù)字范圍,如{1:7}。
● 元素名可以是變量名,也可以是SAS自定義的變量,如_ALL_(標示所有定義的變量,但是變量類型需要相同), _NUMERIC_(所有數(shù)字變量)以及_CHARACTER_(所有字符變量),還可以是_TEMPORARY_(臨時變量)。
● <>表示其中的內(nèi)容并非必須有。例如,$只有在數(shù)組元素為字符型時才用到,length也是。數(shù)組元素及其初始值也并非必需,如果指定數(shù)組元素初始值的話,應(yīng)該在小括號中指定。
程序2-14 定義數(shù)組
*===定義數(shù)組; *===sbp1-sbp7是sbp1到sbp7的縮略寫法; array sbp{7} sbp1-sbp7; array dbp{1:7} dbp1-dbp7; *===帶初始值; array sbp{1:7} sbp1-sbp7 (163164 167171 155158 154); array dbp{7} dbp1-dbp7 (98 99 92 94 95 93 93); *===定義二維數(shù)組; array bp{2,1:7} sbp1-sbp7 dbp1-dbp7 ; array bp{2,7} sbp1-sbp7 dbp1-dbp7 (163164 167171 155158 154 98 99 92 94 95 93 93);
2.訪問數(shù)組
訪問數(shù)組的元素時,我們需要告訴SAS數(shù)組元素的地址,數(shù)組中元素的地址用數(shù)組名加角標的形式arrayname{i} 表示。配合前面已經(jīng)介紹過的DO循環(huán)語句,我們可以遍歷數(shù)組中的所有元素(見圖2-13),進行各種數(shù)據(jù)操作,如果希望進行前面提到的加減校正,把PUT語句換成賦值語句即可。

圖2-13 遍歷數(shù)組元素結(jié)果
程序2-15 訪問數(shù)組元素
datatmp; *===定義數(shù)組; array sbp{7} sbp1-sbp7 (163164 167171 155158 154); array dbp{7} dbp1-dbp7 (98 99 92 94 95 93 93); array bp{2,7} sbp1-sbp7 dbp1-dbp7 (163164 167171 155158 154 98 99 92 94 95 93 93); *===遍歷一維數(shù)組; do i=1to 7; put "第" i "次測量的SBP為:" sbp{i}; put "第" i "次測量的DBP為:" dbp{i}; end; *===遍歷二維數(shù)組; do m=1to 2; do n=1to 7; put "血壓類型為:" m ",血壓測量次數(shù)為:" n ",血壓測量值為:" bp{m,n}; end; end; run;
→2.4.6 函數(shù)與CALL例程
在SAS里,特別是DATA步中,如果希望更加方便、快捷地處理數(shù)據(jù),我們就必須了解函數(shù)和CALL例程。SAS函數(shù)可以接收參數(shù),執(zhí)行一些運算和操作,然后返回一個值。CALL例程與SAS函數(shù)類似,不過不能用于賦值的語句或表達式中。我們通過一個簡單的例子感受下函數(shù)和CALL例程的應(yīng)用。
程序2-16 函數(shù)與例程應(yīng)用示例
data_null_; length FullName_ByFunction FullName_ByRoutine $10; FamilyName="Gu"; GivenName="Hongqiu"; *===用函數(shù)生成全名; FullName_ByFunction=catx(" ",GivenName, FamilyName); *===用例程生成全名; call catx(" ",FullName_ByRoutine, GivenName, FamilyName ); *===Log中查看結(jié)果; put "Fullname Generatedy by Function: " FullName_ByFunction; put "Fullname Generatedy by Routine: " FullName_ByRoutine; run;
筆者粗略統(tǒng)計了下,SAS中有將近30多類,總計達520個函數(shù)。這是一個比較龐大的體系,也是一個非常有力的武器,我們將在第6章專門論述。
→2.4.7 結(jié)構(gòu)化查詢語言SQL
SQL是結(jié)構(gòu)化查詢語言(Structured Query Language)的簡稱,自1970年IBM開發(fā)以來,作為關(guān)系型數(shù)據(jù)庫查詢工具的標準化語言而廣泛使用。SAS自6.06版本引入SQL后,一直在增強完善其功能及其與SAS軟件的兼容性,目前SAS 9中的SQL已經(jīng)非常強大。通過SQL,我們可以進行簡單查詢、子查詢,不用排序就可以進行表的連接、集合運算、創(chuàng)建視圖和表、創(chuàng)建宏變量等一系列操作。本小節(jié)我們僅就SQL語言做一概要式介紹,具體的應(yīng)用我們會結(jié)合后面的實例再討論。
SQL最簡單的應(yīng)用就是用SELECT語句做查詢。SELECT語句包含了一系列有序的從句,具體可見語法2-2。
Help中<>表示里面的東西選用。因此,必用的就只有SELECT和FROM了,比如下面的例子就用SQL查看sashelp.class中的姓名、性別以及年齡。

語法2-2 PROC SQL SELECT語句語法參考卡片
程序2-17 最簡單的一個SQL過程
proc sql; select name, sex, age from sashelp.class; quit;
當然其他從句也是非常實用的。比如,用WHERE可以進行條件篩選,用GROUP BY可以進行分組統(tǒng)計,用HAVING可以對分組統(tǒng)計的結(jié)果進行條件篩選,用ORDER BY可以對結(jié)果進行排序。初接觸時,可能對這些從句的順序記憶有些混淆,筆者個人就用SFW、GHO來記憶它。sfw是一種位圖格式文件的擴展名,gho是ghost鏡像文件的擴展名。
下面是一個完整的,利用了所有SELECT從句的例子。目的是先按性別分組統(tǒng)計人數(shù)、平均身高,然后挑出平均身高大于62的組,最后按人數(shù)多少排序。
程序2-18 PROC SQL SELECT語句全從句示例
proc sql; select sex, count(name) as cnt_name ,mean(height) as m_height from sashelp.class where age>=12 group by sex having m_height>62 order by cnt_name; quit;
→2.4.8 SAS宏MACRO
MACRO(宏)這個術(shù)語可能對我們來說并不陌生,宏就是實現(xiàn)自動化操作的一種工具。在EXCEL里我們就曾接觸過,只是大部分人很少用而已。在SAS里,宏工具是一個用來自動化和定制化SAS代碼的文本處理工具。
SAS的強大,很大一部分原因就是宏工具的存在。宏的本質(zhì)是文本替換,但是通過文本替換,可以實現(xiàn)SAS代碼的自動化生成,動態(tài)生成以及SAS代碼的條件結(jié)構(gòu),也就是說,不僅可以讓SAS代碼自己去寫SAS代碼,而且還可以根據(jù)不同的條件寫不同的代碼,這很符合“元編程”的理念。也正是因為這樣,很多SAS開發(fā)者,瘋狂開發(fā)自己的宏,從而避免很多重復(fù)性的代碼編寫工作,實現(xiàn)更多自動化、智能化的處理。
SAS宏語言分為兩大塊:宏變量和宏程序。宏變量是不必限定在DATA步使用的變量,即獨立于數(shù)據(jù)集的變量。宏變量分為系統(tǒng)宏變量和用戶自定義宏變量。最常規(guī)的情況下,我們可以用%LET語句定義宏變量,%PUT語句查看宏變量。正如前面所說,宏本質(zhì)是文本替換,宏變量也是用簡單的文本去替換更長更復(fù)雜的文本。例如,我們可用一小段文本“PUMC”替換更長的“Peking Union Medical College”。
程序2-19 宏變量
*===自定義; %let PUMC=Peking Union Medical College; *===查看系統(tǒng)自帶; %put &sysdate; *===查看自定義; %put &PUMC;
宏程序同宏變量類似,不過宏程序還有其他特性:①可以包含編程語句,包括DATA步和PROC語句;②可以接受參數(shù)。比如,我們可以定義一個打印指定數(shù)據(jù)集、指定變量的宏。在定義宏程序時,用%MACRO開頭,用%END結(jié)尾,使用宏時,用%宏名稱即可。
程序2-20 MACRO定義和調(diào)用

關(guān)于宏,本節(jié)僅作概念性介紹,具體的內(nèi)容我們將在第10章詳細討論。
- 演進式架構(gòu)(原書第2版)
- Web應(yīng)用系統(tǒng)開發(fā)實踐(C#)
- 在最好的年紀學Python:小學生趣味編程
- Vue.js前端開發(fā)基礎(chǔ)與項目實戰(zhàn)
- Java虛擬機字節(jié)碼:從入門到實戰(zhàn)
- INSTANT OpenNMS Starter
- 快速念咒:MySQL入門指南與進階實戰(zhàn)
- Mastering Linux Network Administration
- 精通Linux(第2版)
- Java程序設(shè)計
- C語言程序設(shè)計
- 好好學Java:從零基礎(chǔ)到項目實戰(zhàn)
- 持續(xù)集成與持續(xù)交付實戰(zhàn):用Jenkins、Travis CI和CircleCI構(gòu)建和發(fā)布大規(guī)模高質(zhì)量軟件
- Django 3.0應(yīng)用開發(fā)詳解
- Node.js區(qū)塊鏈開發(fā)