SAS ® Global Forum 2014 March Washington, DC Arthur Tabachneck Toronto, ON Canada Tom Abernathy New York, NY Matt Kastin Penn Valley, PA
2 Have you ever run into problems or limitations in exporting SAS datasets to Excel? Question
3 Regardless of whether you said yes or no: Would you like to be able to: export without running into 32/64 bit clashes or needing SAS/Access for PC File Formats?export without running into 32/64 bit clashes or needing SAS/Access for PC File Formats? export by simply clicking on a file in the SAS Explorer window?export by simply clicking on a file in the SAS Explorer window? include a row that has variable names or labels?include a row that has variable names or labels? export a table to a specific range?export a table to a specific range? add a table to an existing worksheet?add a table to an existing worksheet? add a worksheet to an existing workbook?add a worksheet to an existing workbook? create a worksheet based on an Excel template?create a worksheet based on an Excel template? copy a file to your system's clipboard?copy a file to your system's clipboard?
4 what the solution looks like Right click on a dataset name in the SAS Explorer window
5 Then select the desired Action (i.e., press hot key (E) or point and left-click)
6 The Workbook will automagically be created
7 Left-click anywhere in the SAS Explorer Window how to get those capabilities
8 Left-click on Tools, move your mouse to Options→Explorer how to get those capabilities
9 Left-click on Members how to get those capabilities
10 Then double left-click on Table how to get those capabilities
11 left-click on Add an Add Action screen will appear and an Add Action screen will appear how to get those capabilities
12 Type the text you want to add to the menu &Export to Excel Action: &Export to Excel It will appear on the menu as: Export to Excel Note: You can make one character a hotkey by preceding it with an ampersand how to get those capabilities
13 Left click in the Action Command box &Export to Excel how to get those capabilities
14 Action Commands only accept up to 255 characters The 255 character limitation can be circumvented by submitting a macro When using gsubmit in an Action Command, everything between the two single quotes will be submitted some key points about the Action Command % has a special meaning in Action Commands thus, if you need to use a % (e.g., to call a macro), use two %s When a SAS dataset is selected %8b and %32b can be used to refer to the libname and filename, respectively
15 that can be used to drive hundreds of different actions dependent upon how it is called gsubmit '%exportxl(data=%8b.%32b, type=P, method=E)'; will run proc export on the dataset Note: type=P Requires SAS/Access for PC File Formats gsubmit '%exportxl(data=%8b.%32b,metho &Export to Excel our paper presents a SAS macro: %exportxl for example
16 click on OK to exit the Add Action screen gsubmit '%exportxl(%8b,%32b,P,YES)'; &Export to Excel after you have entered an action command
17 click on OK to exit the Table Options screen then, after you've entered as many actions as you care to create
18 Once you have completed those steps whenever you right click on a file in the SAS Explorer window, and select an action, the action will be taken
19 if range, template or templatesheet = Y enter the requested value and then press your key a screen like the following will appear
20 gsubmit '%exportxl(data=%8b.%32b, type=N, method=E)'; will use vbs to create a new Excel Workbook gsubmit '%exportxl(data=%8b.%32b, type=C, method=E)'; will copy the dataset to your system's clipboard gsubmit '%exportxl(data=%8b.%32b, type=A, method=E)'; will use vbs to create a new WorkSheet gsubmit '%exportxl(data=%8b.%32b, type=M, range=F3, method=E)'; will use vbs to modify an existing WorkSheet, starting the added table at cell F3 gsubmit '%exportxl(data=%8b.%32b, type=N, usenames=L, method=E)'; will use vbs to create a new Workbook with the first row containing the variables' labels some action command examples:
21 the macro can also be called from code %exportxl(data=sashelp.class, outfile=c:\class.xlsx) for example:
22 data is the dataset you want to export outfile is the Excel Workbook you want to create or modify type can have one of five values: P to run PROC EXPORT N to use VBS to create a new Workbook M to use VBS to modify an existing Worksheet A to use VBS to add a new Worksheet C to copy a file to your system's clipboard usenames can have one of three values: Y to include a row of variable names L to include a row of variable labels N to not include a variable name or label header record the macro's named parameters (default in purple)
23 range can either be null or A1 to indicate A1 as the first cell in range Y to allow user input during run A1 or any valid Excel cell where you want a table to start sheet is the Excel Worksheet you want to create or modify. If null default value becomes SAS dataset name replace can have one of two values: Y to replace an existing Workbook N to ask, first, if an existing Workbook is found method can have one of two values: E to indicate that the macro was run from SAS Explorer I to indicate that macro was run from code the macro's named parameters (continued)
24 template can either be null indicates that no template will be used the full path of a valid Excel template Y to allow user input during run templatesheet can either be null indicating that no template will be used the name of the sheet you want to use in the specified template Y to allow user input during run the macro's named parameters (continued)
25 if type=N, M or A, without Replace i.e., the program will ask you whether it should, or shouldn't, replace the existing file a screen like the following will appear
26 have you ever used an Excel template? an Excel template is simply an Excel file that has been saved as a template file It can include such things as: font choice, color, size, etc. highlighting formulas graphs
27 after creating workbook just save it as a template
28 then, with code like the following: %exportxl(data=sashelp.class, template=c:\art\template.xltx, templatesheet=Template, outfile=c:\art\tclass.xlsx, sheet=N1)
29 you can create:
30 and, not only can you do more, but only requires base SAS runs 35 times faster than ODS methods creates an Excel file that opens more quickly than any other method extremely simple to code only available for systems that allow both VBS and the clipbrd access method (e.g., Windows compatible) provides capabilities not available with other methods
31 Save the file as exportxl.sas in a directory that exists in your SASAUTOS* path * see: where to get the macro Copy the SAS program from: User: Art297
32 %macro exportxl(data=, outfile=, sheet=, type=N, usenames=Y, range=A1, replace=Y, template=, templatesheet=, method=I); %if %sysfunc(countw(&data.)) eq 2 %then %do; %let libnm=%scan(&data.,1); %let filenm=%scan(&data.,2); %end; %else %do; %let libnm=work; %let filenm=&data.; %end; %if %length(&outfile.) lt 1 %then %do; %let outfile=%sysfunc(pathname(&libnm.))\&filenm..xlsx; %let sheet=&filenm.; %end; how the macro works
33 %macro exportxl(data=, outfile=, sheet=new, type=N, usenames=Y, range=A1, replace=Y, template=, templatesheet=, method=I); %if %sysfunc(countw(&data.)) eq 2 %then %do; %let libnm=%scan(&data.,1); %let filenm=%scan(&data.,2); %end; %else %do; %let libnm=work; %let filenm=&data.; %end; %if %length(&outfile.) lt 1 %then %do; %let outfile=%sysfunc(pathname(&libnm.))\&filenm..xlsx; %let sheet=&filenm.; %end; how the macro works
34 %macro exportxl(data=, outfile=, sheet=new, type=N, usenames=Y, range=A1, replace=Y, template=, templatesheet=, method=I); %if %sysfunc(countw(&data.)) eq 2 %then %do; %let libnm=%scan(&data.,1); %let filenm=%scan(&data.,2); %end; %else %do; %let libnm=work; %let filenm=&data.; %end; %if %length(&outfile.) lt 1 %then %do; %let outfile=%sysfunc(pathname(&libnm.))\&filenm..xlsx; %let sheet=&filenm.; %end; how the macro works
35 %macro exportxl(data=, outfile=, sheet=new, type=N, usenames=Y, range=A1, replace=Y, template=, templatesheet=, method=I); %if %sysfunc(countw(&data.)) eq 2 %then %do; %let libnm=%scan(&data.,1); %let filenm=%scan(&data.,2); %end; %else %do; %let libnm=work; %let filenm=&data.; %end; %if %length(&outfile.) lt 1 %then %do; %let outfile=%sysfunc(pathname(&libnm.))\&filenm..xlsx; %let sheet=&filenm.; %end; how the macro works
36 %if %upcase(&type.) eq P %then %do; proc export data=&libnm..&filenm. outfile= "&outfile." dbms=xlsx %if %upcase(&replace.) eq Y %then replace; ; %if &sheet. ne "" %then sheet="&sheet.";; run; %end; how the macro works
37 %else %do; %if %upcase(&range.) eq Y %then %do; data _null_; window range rows=8 columns=80 irow=1 icolumn=2 color=black 'Enter the upper left cell where range should begin (e.g. D5): ' color=gray range $41. required=yes attr=underline color=yellow; DISPLAY range blank; call symputx('range',range); stop; run; %end; %else %if %length(&range.) lt 2 %then %do; %let range=A1; %end; how the macro works Display window to let users identify range
38 %if %upcase(&template.) eq Y %then %do; data _null_; window template rows=8 columns=80 irow=1 icolumn=2 color=black 'Enter the template path and name: ' color=gray template $41. required=yes attr=underline color=yellow; DISPLAY template blank; call symputx('template',template); stop; run; %end; how the macro works Display window to let users identify template
39 %if %upcase(&templatesheet.) eq YES %then %do; data _null_; window templatesheet rows=8 columns=80 irow=1 icolumn=2 color=black "Enter the template sheet's name: " color=gray templatesheet $41. required=yes attr=underline color=yellow; DISPLAY templatesheet blank; call symputx('templatesheet',templatesheet); stop; run; %end; how the macro works Display window to let users identify templatesheet
40 data _null_; dsid=open(catx('.',"&libnm.","&filenm.")); if dsid eq 0 then do; rc=close(dsid); link err; end; nvar=attrn(dsid,'nvars'); call symputx('nvar',nvar); rc=close(dsid); err: do; m = sysmsg(); put m; stop; end; run; how the macro works Get number of variables
41 data _null_; rc=filename('clippy',' ','clipbrd'); if rc ne 0 then link err; fid=fopen('clippy','o',0,'v'); if fid eq 0 then link err; dsid=open(catx('.',"&libnm.","&filenm.")); if dsid eq 0 then do; rc=fclose(fid); rc=filename('clippy'); link err; end; rc=attrn(dsid,'any'); if rc ne 1 then do; rc=fclose(fid); rc=close(dsid); rc=filename('clippy'); link err; end; how the macro works Open the clipbrd so that we can write to it
42 data _null_; rc=filename('clippy',' ','clipbrd'); if rc ne 0 then link err; fid=fopen('clippy','o',0,'v'); if fid eq 0 then link err; dsid=open(catx('.',"&libnm.","&filenm.")); if dsid eq 0 then do; rc=fclose(fid); rc=filename('clippy'); link err; end; rc=attrn(dsid,'any'); if rc ne 1 then do; rc=fclose(fid); rc=close(dsid); rc=filename('clippy'); link err; end; how the macro works Open the SAS dataset so that we can read it
43 data _null_; rc=filename('clippy',' ','clipbrd'); if rc ne 0 then link err; fid=fopen('clippy','o',0,'v'); if fid eq 0 then link err; dsid=open(catx('.',"&libnm.","&filenm.")); if dsid eq 0 then do; rc=fclose(fid); rc=filename('clippy'); link err; end; rc=attrn(dsid,'any'); if rc ne 1 then do; rc=fclose(fid); rc=close(dsid); rc=filename('clippy'); link err; end; how the macro works Ensure dataset has variables and data
44 array v{&nvar.}; do i = 1 to &nvar.; v{i}=ifn( vartype(dsid,i)='C',1,2); %if %upcase(&usenames.) ne N %then %do; if i gt 1 then rc=fput(fid,'09'x); %if %upcase(&usenames.) eq Y %then %do; rc=fput(fid,varname(dsid,i)); %end; %else %do; if missing(varlabel(dsid,i)) then rc=fput(fid,varname(dsid,i)); else rc=fput(fid,varlabel(dsid,i)); %end; end; %if %upcase(&usenames.) ne N %then %do; rc=fwrite(fid);; %end; how the macro works declare array
45 array v{&nvar.}; do i = 1 to &nvar.; v{i}=ifn( vartype(dsid,i)='C',1,2); %if %upcase(&usenames.) ne N %then %do; if i gt 1 then rc=fput(fid,'09'x); %if %upcase(&usenames.) eq Y %then %do; rc=fput(fid,varname(dsid,i)); %end; %else %do; if missing(varlabel(dsid,i)) then rc=fput(fid,varname(dsid,i)); else rc=fput(fid,varlabel(dsid,i)); %end; end; %if %upcase(&usenames.) ne N %then %do; rc=fwrite(fid);; %end; how the macro works Assign values to array based on variable type
46 array v{&nvar.}; do i = 1 to &nvar.; v{i}=ifn( vartype(dsid,i)='C',1,2); %if %upcase(&usenames.) ne N %then %do; if i gt 1 then rc=fput(fid,'09'x); %if %upcase(&usenames.) eq Y %then %do; rc=fput(fid,varname(dsid,i)); %end; %else %do; if missing(varlabel(dsid,i)) then rc=fput(fid,varname(dsid,i)); else rc=fput(fid,varlabel(dsid,i)); %end; end; %if %upcase(&usenames.) ne N %then %do; rc=fwrite(fid);; %end; how the macro works Assign variable names or labels
47 array v{&nvar.}; do i = 1 to &nvar.; v{i}=ifn( vartype(dsid,i)='C',1,2); %if %upcase(&usenames.) ne N %then %do; if i gt 1 then rc=fput(fid,'09'x); %if %upcase(&usenames.) eq Y %then %do; rc=fput(fid,varname(dsid,i)); %end; %else %do; if missing(varlabel(dsid,i)) then rc=fput(fid,varname(dsid,i)); else rc=fput(fid,varlabel(dsid,i)); %end; end; %if %upcase(&usenames.) ne N %then %do; rc=fwrite(fid);; %end; how the macro works Write variable names/ labels
48 do i=1 to attrn(dsid,'nlobs'); rc=fetchobs(dsid,i); do j=1 to &nvar.; if j gt 1 then rc=fput(fid,'09'x); if (v[j] eq 1) then rc=fput(fid, getvarc(dsid,j)); else do; fmt=varfmt(dsid,j) ; if missing(fmt) then fmt='best12.'; rc=fput(fid,putc(putn(getvarn(dsid,j ),fmt),'$char12.')); end; rc=fwrite(fid); end; rc=fclose(fid); rc=close(dsid); rc=filename('clippy'); stop; how the macro works Get data and formats and write tab-delimited records
49 do i=1 to attrn(dsid,'nlobs'); rc=fetchobs(dsid,i); do j=1 to &nvar.; if j gt 1 then rc=fput(fid,'09'x); if (v[j] eq 1) then rc=fput(fid, getvarc(dsid,j)); else do; fmt=varfmt(dsid,j) ; if missing(fmt) then fmt='best12.'; rc=fput(fid,putc(putn(getvarn(dsid,j ),fmt),'$char12.')); end; rc=fwrite(fid); end; rc=fclose(fid); rc=close(dsid); rc=filename('clippy'); stop; how the macro works Cleanup
50 how the macro works err: do; m = sysmsg(); put m; stop; end; run; Abort if errors detected
51 %if %upcase(&type.) eq N or %upcase(&type.) eq M or %upcase(&type.) eq A %then %do; data _null_; length script filevar $256; script = catx('\',pathname('WORK'),'PasteIt.vbs'); filevar = script; script="'"||'cscript "'||trim(script)||'"'||"'"; call symput('script',script); file dummy1 filevar=filevar recfm=v lrecl=512; put 'Dim objExcel'; put 'Dim Newbook'; %if %length(&template.) gt 1 %then %do; %if %upcase(&type.) eq A %then put 'Dim OldBook';; put 'Set objExcel = CreateObject("Excel.Application")'; put 'objExcel.Visible = True'; %if %upcase(&type.) eq N %then %do; script=catt('Set Newbook = objExcel.Workbooks.Add("', "&template.",'")'); put script; script=catt('objExcel.Sheets("',"&TemplateSheet.",'").Select'); put script; how the macro works If type eq N, M or A create a VBS script called PasteIt.vbs
52 Dim objExcel Dim Newbook Set objExcel = CreateObject("Excel.Application") objExcel.Visible = True Set Newbook = objExcel.Workbooks.Add("c:\template.xltx") objExcel.Sheets("Template").Select objExcel.Sheets("Template").Name = "class" objExcel.Visible = True objExcel.Sheets("class").Range("A1").Activate objExcel.Sheets("class").Paste objExcel.Sheets("class").Range("A1").Select objExcel.DisplayAlerts = False NewBook.SaveAs("c:\class.xlsx") objExcel.Workbooks.Close objExcel.DisplayAlerts = True objExcel.Quit if you were to run: %exportxl(data=sashelp.class, template=c:\template.xltx, templatesheet=Template, outfile=c:\class.xlsx) the code will create:
53 Dim objExcel Dim Newbook Dim OldBook Set objExcel = CreateObject("Excel.Application") objExcel.Visible = True strFile="c:\art\class.xlsx" Set OldBook=objExcel.Workbooks.Open("c:\class.xlsx") Set Newbook = objExcel.Workbooks.Add("c:\template.xltx") objExcel.Sheets("Template").Select objExcel.Sheets("Template").Name ="class2" objExcel.Visible = True objExcel.Sheets("class2").Range("A1").Activate objExcel.Sheets("class2").Paste objExcel.Sheets("class2").Range("A1").Select objExcel.Sheets("class2").Move,OldBook.Sheets( OldBook.Sheets.Count ) objExcel.DisplayAlerts = False OldBook.SaveAs("c:\class.xlsx") objExcel.Workbooks.Close objExcel.DisplayAlerts = True objExcel.Quit if you were to run: %exportxl(data=sashelp.class, template=c:\template.xltx, type=A, templatesheet=Template, outfile=c:\class.xlsx, sheet=class2) the code will create:
54 Dim objExcel Dim Newbook Dim NewSheet Dim inCount Set objExcel = CreateObject("Excel.Application") Set Newbook = objExcel.Workbooks.Add() objExcel.Visible = True inSheetCount = Newbook.Application.Worksheets.Count set NewSheet = Newbook.Sheets.Add(,objExcel.WorkSheets(inCount)) objExcel.DisplayAlerts = False i = inCount Do Until i = 0 Newbook.Worksheets(i).Delete i = i - 1 Loop Newbook.Sheets(1).Name="class" Newbook.Sheets("class").Select Newbook.Sheets("class").Range("A1").Activate Newbook.Sheets("class").Paste NewSheet.SaveAs("c:\class.xlsx") objExcel.Workbooks.Close objExcel.DisplayAlerts = True objExcel.Quit if you were to run: %exportxl(data=sashelp.class, outfile=c:\class.xlsx) the code will create:
55 Dim objExcel Dim Newbook Dim inCount Dim strFile Set objExcel = CreateObject("Excel.Application") strFile="c:\class.xlsx" objExcel.Visible = True objExcel.Workbooks.Open strFile inCount = objExcel.Application.Worksheets.Count set NewBook = objExcel.Sheets.Add(,objExcel.WorkSheets(inCount)) objExcel.Sheets(inCount + 1).Name="class2" objExcel.Sheets("class2").Select objExcel.Visible = True objExcel.Sheets("class2").Range("A1").Activate objExcel.Sheets("class2").Paste objExcel.DisplayAlerts = False Newbook.SaveAs("c:\class.xlsx") objExcel.Workbooks.Close objExcel.DisplayAlerts = True objExcel.Quit if you were to run: %exportxl(data=sashelp.class, outfile=c:\class.xlsx, type=A, sheet=class2) the code will create:
56 Dim objExcel Dim Newbook Set objExcel = CreateObject("Excel.Application") Set Newbook = objExcel.Workbooks.Open("c:\class.xlsx") Newbook.Sheets("class").Select Newbook.Sheets("class").Range("f1").Activate Newbook.Sheets("class").Paste objExcel.DisplayAlerts = False Newbook.SaveAs("c:\class.xlsx") objExcel.Workbooks.Close objExcel.DisplayAlerts = True objExcel.Quit if you were to run: %exportxl(data=sashelp.class, range=f1, type=M, outfile=c:\class.xlsx, sheet=class) the code will create:
57 data _null_; call system(&script.); run; %end; %mend exportxl; how the macro works Run the VBS script where &script. = cscript WorkDirectoryPath\PasteIt.vbs
58 What the ExportXL macro is and where you can download it How the macro works How you can set up Action Commands, or call the macro directly from base SAS or EG, to accomplish things you can't do with proc export summary of what I just presented: How you can create Action Commands in the SAS Explorer window
Your comments and questions are valued and encouraged Contact the Authors Arthur Tabachneck, Ph.D. Analyst Finder, Inc. Toronto, ON Tom Abernathy Pfizer, Inc. New York, NY Matt Kastin I-Behavior, Inc. Penn Valley, PA