2013-09-25 360 views
4

我需要在一個SAS數據集中導入大量的csv文件。它們都具有相同的數據結構(相同的變量,第一行中的變量名稱)。我通常在SQL中工作,但我被迫參加SAS中的這個特定項目,而我只具備基礎知識。在SAS中追加多個CSV文件

目前,我的代碼看起來是這樣的:

proc import out=work.data 
    datafile = file1.csv 
    DBMS=CSV REPLACE; 
    GETNAMES=YES; 
    DATAROW=2; 

proc import out=work.newData 
    datafile = file2.csv 
    DBMS=CSV REPLACE; 
    GETNAMES=YES; 
    DATAROW=2; 

proc append base=work.data 
      data=work.newData force;  
run; 

等了file3.csv ... file4.csv。

確實有一種更優雅的方式來做到這一點,即循環顯示一個文件夾上的所有csv文件,而無需明確寫入(有幾千個文件)。

感謝您的幫助。

回答

4

您需要計算出輸入語句,而不是使用PROC IMPORT(儘管如果您使用PROC IMPORT一次,它會禮貌地將該輸入代碼寫入日誌中,然後您可以使用通配符) :

data mydata; 
infile "c:\temp\*.csv" dlm=',' missover lrecl=32767; 
input 
myvar1 
myvar2 $ 
myvar3 
myvar4 :date9. 
; 
run; 

存在其他一些選項;例如參見https://communities.sas.com/message/182012#182012以用於其他方式來執行它。

+1

生成的代碼一個好的技巧與PROC IMPORT是使用運行 - >調用最後提交在IDE中。這會將生成的代碼放在活動代碼窗口的頂部。 – DomPazz

+0

很好,謝謝。當我使用firstobs = 2時,它只跳過第一個文件的第一行(其中包含變量名稱),幷包含後續文件的第一行,導致一堆缺失值。有沒有辦法解決? – user2816263

+0

是的,有點。您可以使用幾個選項之一('eov'或'filename')來查看文件何時更改,以及何時有選擇地跳過記錄。然而,你需要一個簡單的輸入('input @;')來觸發前一個文件的結尾(SAS在讀取另一行之前不會看到它)。 – Joe

2

import過程接受由filename語句創建的fileref,並且filename語句接受多個文件。因此,你可以做到以下幾點:

filename csvs ('file1.csv', 'file2.csv', 'file3.csv', 'file4.csv'); 

proc import out=work.data 
datafile = csvs 
DBMS=CSV REPLACE; 
GETNAMES=YES; 
DATAROW=2; 
run; 

我不能完全肯定這將如何與多個CSV的每一個有一個標題的工作,但我似乎記得SAS識別每個新文件,並跳過第一行作爲根據您的DATAROW=2聲明。

或者您可以使用宏來遍歷文件夾中的所有文件,導入它們,並將它們附加到您的主集中。 This answer here應該可以幫助您獲取文件夾中所有文件的列表。然後,你可以這樣做:

%macro importcsvs (folder, outputname); 
    /* I assume this is your macro that takes a folder and returns a dataset */ 
    /* (called filelist) containing the filename in variable: file */ 
    %getallfilesinfolder(&folder, filelist); 

    /* determine number of files to read */ 
    %let numfiles=0; 
    data _null_; 
    set filelist end=last; 
    if last then call symput('numfiles',put(_n_,best.)); 
    run; 

    %do i=1 %to &numfiles; 
     %let curfile=; 
     data _null_; 
     /* obs and firstobs =i mean you only read item i in the dataset */ 
     set filelist (obs=&i firstobs=&i); 
     call symput('curfile',file); 
     run; 

     filename csv "&curfile"; 
     proc import out=work.data 
     datafile = csv 
     DBMS=CSV REPLACE; 
     GETNAMES=YES; 
     DATAROW=2; 
     run; 

     data work.&outputname; 
     set 
     %if %sysfunc(exist(work.&outputname)) %then %do; 
      work.&outputname 
     %end; 
      work.data; 
     run; 
    %end; 

%mend; 

%importcsvs(/your/folder/with/csvs, newData); 
0

將所有文件複製到文件夾和改變它作爲當前文件夾中的SAS

x 'cd C:\Users\csvfolder';/*Your-folder-path*/ 

filename csv ('*.csv'); 

proc import out=work.allcsv 
datafile = csv DBMS=CSV REPLACE; 
GETNAMES=yes; 
run; 
+1

您可以在同一個文件名語句中使用多個文件夾路徑,並在其中使用通配符,因此在導入它們之前無需將所有文件複製到一個文件夾中。 – user667489

2

爲了擴大對喬的回答一點 - 這裏有一個如何的例子導入多個CSV文件,所有與標題行:

  • 在一個數據步驟
  • 沒有每個SAS處理一個時間生成日誌在筆記或錯誤標題行
  • 沒有包括在所得到的SAS數據集

代碼中的任何標題行的:

/*First make a few CSV files to import*/ 

%macro generate_csvs(n); 
    %do i = 1 %to &n; 
     proc export 
      data = sashelp.class 
      dbms = csv 
      outfile = "C:\temp\class&n..csv"; 
     run; 
    %end; 
%mend generate_csvs; 

%generate_csvs(2); 

/*Import the CSV files*/ 

data want; 
    length _filename_ $32; 
    infile "c:\temp\class*.csv" dlm = ',' filename = _filename_; 
    input @; 
    if _filename_ ne lag1(_filename_) then delete; 
    input name :$8. sex :$1. age :8. height :8. weight :8.; 
run; 

注:

  • _filename_不被更新,直到SAS一直試圖讀過一個文件的末尾 - input @;在沒有實際輸入任何數據的情況下觸發此操作,同時保持當前行爲第二個非標題行的語句。
  • _filename_未包括在輸出數據集中,但是如果您想跟蹤每條記錄的來自哪個csv,則可以輕鬆地創建另一個變量作爲其副本。
  • 格式修飾符:允許輸入語句讀取不在固定寬度列中的格式化變量。
0

SAS宏語言中的循環方法應該可以工作。例如:

%macro loops(data); 

data test;infile "c:\folder\&&data..csv" dsd missover lrecl=xyz dlm= 
      firstobs= and so on; 
input var1-var20; 
run; 

proc append data=test base=AllCSVFiles; 
run; 

%mend; 
%loops(csvdatafile) 
%loops(etc...) 

這是非常通用的代碼。如果你可以創建一個只包含CSV數據文件名的文件,那麼你可以調用一個新的宏內環路%:

data files;infile 'c:\folder\FileWithCsvDataFileNames' options as above; 
length csvfilename $32.; 
input csvfilename; 
run; 

%macro callmacro; 

data _null_;set files nobs=nobs; 
call symput('TotFiles',put(nobs,8.)); 
run; 

%do a=1 %to &&TotFiles; 

data _null_;set files; 
if _n_=&&a; 
call symputx('csvdatafilex',put(csvfilename,$32.)); 
run; 

%loops(&&csvdatafilex) 

%end; 

%mend; 
%callmacro