SAS編程:SQL的數(shù)據(jù)集操作用法簡(jiǎn)談

最近,我在處理數(shù)據(jù)集操作中,使用SQL語(yǔ)句比較頻繁。最直接的原因是,數(shù)據(jù)集拼接時(shí)不需要排序。用得多,自然會(huì)遇到不少問(wèn)題,也查詢了不少語(yǔ)法內(nèi)容。在這里匯總使用注意點(diǎn),方便自己和讀者使用時(shí)進(jìn)行查看。

1. 數(shù)據(jù)觀測(cè)去重-DISTINCT

如果需要對(duì)所選變量進(jìn)行去重,可以在SELECT語(yǔ)句中使用DISTINCT關(guān)鍵字。需要注意,DISTINCT的作用是針對(duì)SELECT語(yǔ)句中的所有變量,所以一個(gè)SELECT語(yǔ)句只需要一個(gè)DISTINCT關(guān)鍵字(多個(gè)會(huì)報(bào)語(yǔ)法錯(cuò)誤)。錯(cuò)誤示范如下:

proc sql noprint;
  create table test1 as
    select distinct sex, distinct name
    from sashelp.class
  ;
quit;
log1

2. 觀測(cè)的篩選1-Where語(yǔ)句

與Data步類似,SQL可以通過(guò)Where語(yǔ)句來(lái)選擇符合條件的記錄。但是,如果條件語(yǔ)句中引用的了新建的變量,會(huì)出現(xiàn)語(yǔ)法錯(cuò)誤,比如篩選出SASHelp.Class數(shù)據(jù)集中BMI大于20的人(數(shù)據(jù)集中身高和體重的單位是英寸、磅,需要轉(zhuǎn)換)。

proc sql noprint;
  create table test2 as
    select *, (weight*0.45359237)/(height*0.0254)**2 as bmi
    from sashelp.class
    where bmi > 20
   ;
quit;
log2

與Data步中相同,Where語(yǔ)句是在處理數(shù)據(jù)之前進(jìn)行篩選,也就是在SELECT語(yǔ)句之前起作用,由于原表中沒(méi)有BMI變量,所以SAS運(yùn)行會(huì)報(bào)錯(cuò)。解決方法是,在變量前添加CALCULATED關(guān)鍵字,來(lái)表明改變量是新生成的,從而避免報(bào)錯(cuò)。

proc sql noprint;
  create table test2 as
    select *, (weight*0.45359237)/(height*0.0254)**2 as bmi
    from sashelp.class
    where calculated bmi > 20
   ;
quit;
Output

3. 觀測(cè)的篩選2-Having語(yǔ)句

在Data步中,Where語(yǔ)句在處理數(shù)據(jù)之前進(jìn)行篩選,if語(yǔ)句在處理數(shù)據(jù)之后進(jìn)行篩選。與Data步類似,SQL中也有在數(shù)據(jù)處理之后進(jìn)行篩選的語(yǔ)句——Having。在Having語(yǔ)句中,可以直接調(diào)用新生成的變量。不過(guò),從運(yùn)算效率角度考慮,推薦在處理數(shù)據(jù)之前進(jìn)行篩選。

proc sql noprint;
  create table test3 as
    select *, (weight*0.45359237)/(height*0.0254)**2 as bmi
    from sashelp.class
    having bmi > 20
   ;
quit;
Output

4. 數(shù)據(jù)集的拼接

數(shù)據(jù)集的拼接有兩種,豎向拼接和橫向拼接。

4.1 豎向拼接

在Data步中,豎向拼接使用set語(yǔ)句。由于豎向拼接不涉及變量的匹配選擇,所以set語(yǔ)句使用起來(lái)還是簡(jiǎn)單快捷的。

過(guò)程步Append也可以實(shí)現(xiàn)豎向拼接,不過(guò),是將一個(gè)數(shù)據(jù)集中的記錄追加到主數(shù)據(jù)集的后面,并且變量?jī)H包含主數(shù)據(jù)集中的變量。過(guò)程步Append日常工作中,用的比較少,具體語(yǔ)法,讀者可以參考SAS的官方文檔。

SQL中的縱向拼接,使用的是union拼接。union拼接的涉及到的拼接形式不少,但日常工作中的豎向拼接是需要同時(shí)保留拼接表的所有變量的,也就是Data步的set語(yǔ)句的作用。這樣的拼接,使用的是outer union corr。下面簡(jiǎn)單用代碼演示下,為方便展示,使用inobs=選項(xiàng)選取每個(gè)數(shù)據(jù)集的前5條進(jìn)行豎向拼接。

proc sql inobs = 5 noprint;
  create table test1 as
    select name, weight from sashelp.class
      outer union corr
    select name, height from sashelp.class
  ;
quit;
Output
4.2 橫向拼接

工作中常用的橫向拼接有兩種,第一種,保留原有數(shù)據(jù)集的數(shù)據(jù),并從其他數(shù)據(jù)集拼接獲取需要的變量;第二種,保留拼接數(shù)據(jù)集中共同的記錄。

以2個(gè)數(shù)據(jù)集拼接為例,這兩種橫向拼接在Data步中實(shí)現(xiàn)并不復(fù)雜,只是使用merge語(yǔ)句時(shí),各個(gè)數(shù)據(jù)集必須先按照BY變量排好序。如果操作的數(shù)據(jù)集數(shù)量多起來(lái),這一步就瑣碎麻煩了。

以上兩種橫向拼接方式,在SQL中分別對(duì)應(yīng)left joininner join。代碼簡(jiǎn)單演示:

**Left Join;
proc sql noprint;
  create table test1 as
    select a.*, b.*
    from dt1 as  a
      left join dt2 as b
    on a.var1 = b.var1 and a.var2 = b.var2
  ;
quit;

**Inner Join;
proc sql noprint;
  create table test2 as
    select a.*, b.*
    from dt1 as  a
      inner join dt2 as b
    on a.var1 = b.var1 and a.var2 = b.var2
   ;
quit;

5. 如何保留數(shù)據(jù)集的第一條\最后一條記錄?

先介紹在Data步中如何實(shí)現(xiàn)這些功能。常用的方法,借助系統(tǒng)變量_N_,這個(gè)變量是記錄數(shù)據(jù)集觀測(cè)的行數(shù)。只要保留_N_ = 1的記錄,就實(shí)現(xiàn)了保留第一條記錄。

data tmp;
  set sashelp.class;
  if _n_ = 1;
run;

另一種方法,通過(guò)控制讀取數(shù)據(jù)集的記錄數(shù)實(shí)現(xiàn)。數(shù)據(jù)集選項(xiàng)firstobs=、obs=用于控制讀入的起始記錄以及結(jié)束記錄的條數(shù)。只要起始和結(jié)束記錄都是第一條記錄,那么就實(shí)現(xiàn)了讀取第一條記錄了。這個(gè)數(shù)據(jù)集選項(xiàng)在調(diào)試大數(shù)據(jù)集內(nèi)容時(shí),特別實(shí)用,比如先讀?。保埃皸l數(shù)據(jù),等程序完全Run通,再讀入所有數(shù)據(jù)。

data tmp;
  set sashelp.class(obs = 1);
run;

由于我們一般不知道數(shù)據(jù)集的最后記錄數(shù),所以以上兩種方法不適合獲取數(shù)據(jù)集的最后一條記錄。

Data步中Set語(yǔ)句有兩個(gè)選項(xiàng)end=nobs=,前者創(chuàng)建一個(gè)表明是否是數(shù)據(jù)集尾行的臨時(shí)變量,后者創(chuàng)建一個(gè)保存數(shù)據(jù)集記錄數(shù)的臨時(shí)變量。臨時(shí)變量不會(huì)再數(shù)據(jù)集中顯示,通過(guò)賦值給其他變量可以展示出來(lái)。

data tmp;
  set sashelp.class end = a nobs = b;
  aa = a;
  bb = b;
run;
Output

通過(guò)Set語(yǔ)句這兩個(gè)選項(xiàng),可以實(shí)現(xiàn)獲取最后一條記錄。

**end=;
data tmp;
  set sashelp.class end = a;
  if a;
run;

**nobs=;
data tmp;
  set sashelp.class nobs = b;
  if _n_ = b;
run;

那SQL中如何實(shí)現(xiàn)這樣的功能呢?SQL中有一個(gè)“變量”的功能跟_N_類似,這個(gè)變量是monotonic()。這個(gè)內(nèi)容是我在Review公司宏程序發(fā)現(xiàn)的,在SAS官方文檔中也沒(méi)有找到具體的解釋。

proc sql noprint;
  create table tmp as
    select *, monotonic() as num
    from sashelp.class;
quit;
Output

知曉每一行數(shù)據(jù)集的行號(hào),就可以通過(guò)保留行號(hào)的最小值和最大值,來(lái)實(shí)現(xiàn)首條和尾條記錄的保留。

proc sql noprint;
  create table tmp as
    select *, monotonic() as num
    from sashelp.class
    having num = min(num)  or num = max(num)
  ;
quit;
Output

感謝閱讀!若有疑問(wèn),歡迎評(píng)論區(qū)交流!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容