SAS: Exporting Data Subsets to Separate Workbook Tabs in Excel - sas

Question: How can I export subsets of a data set to individual tabs of an Excel workbook (preferably .xlsx) without running PROC EXPORT several times?
My Solution
The data set contains 15 indicators. Unfortunately, the indicators do not have names which can be indexed. This means I cannot put the export procedure into a macro which loops over a counter 15 times and appends the name with the index. The indicators are (not really) things like "car", "truck", "bicycle", "dinosaur", etc.
The solution I came up with was like this:
proc export data = data_set
(where = (indicator = "car"))
outfile = "c:\workbook.xlsx"
dbms = xlsx replace;
sheet = car;
run;
...
proc export data = data_set
(where = (indicator = "dinosaur"))
outfile = "c:\workbook.xlsx"
dbms = xlsx replace;
sheet = dinosaur;
run;
However, this is obviously inefficient and begs for some sort of automation.

You can use the libname facility, which is what proc export uses in the background usually.
libname myexcel xlsx "c:\outwhatever\myfile.xlsx"; *can use XLSX if 9.4+ or EXCEL if earlier;
That gives you a regular libname just as if it were a SAS libname, and you can write to it like so:
data myexcel.sheetname;
set whatever;
run;
Or use PROC COPY or similar.
There are other options (using OLEDB or similar, for example), but libname is simplest. See the documentation for more details.

If you have SAS 9.4 ODS Excel is quite simple and nice, set the sheet_interval option to bygroup and add a prefix for the sheet name.
proc sort data=sashelp.class out=class;
by age;
run;
ods excel file='/folders/myfolders/sample.xlsx' options (sheet_interval='bygroup' sheet_label='Age');
proc print data=class noobs label;
by age;
run;
ods excel close;

Related

Why is my SAS output giving me different results than my proc means statement?

my proc means data is just how I want it. But, when I try to output the data to an excel it does not look the same. How do I fix this?
/*Means average value by state*/
proc means data = merged;
class statename state;
var valueh;
output out = statedata1 MEAN = valueh;
run;
/*Export the Data*/
proc export data = statedata outfile= '/home/...' dbms= xlsx replace;
run;
proc print data = statedata;
run;
The data appears fine but when I output it to an excel it is separating my state and statename variables instead of keeping them combined. Attached is a picture the proc means output as well as the proc print after I exported the data.
The dataset produced does not not need to look like the REPORT produced.
In particular the default for the report is to only include the results that use all of the class variables. And the default for the generated dataset is to include the summary for all possible combinations of the class variables. With 2 class variables there are four possible combinations (which reflected in the _TYPE_ variable). Overall (none), Each one separately and both together.
If you want the report in your Excel file why not use ODS EXCEL.
/*Export the Report*/
ods excel file='/home/...';
proc means data = merged;
class statename state;
var valueh;
run;
ods excel close;
If you only want the results that include both CLASS variables then you could add the NWAY option to the PROC MEANS statement.
proc means data = merged nway;
Or use the TYPES or WAYS statement to control which combinations are produced.
Or just filter in the export.
proc export data = statedata(where=(_type_=3))
outfile= '/home/...' dbms= xlsx replace
;
run;

Saving the query results to csv

I'm wondering if it's possible to save the query results to csv? Without creating views.
I have a large table but need only 2 columns from there to process with python then. Maybe someone can help with it?
Here are three ways
ODS
SQL query can be output to an ODS CSV destination. This approach encompasses the widest possibilities of querying.
ods csv file='c:\temp\query-results.csv';
proc sql;
select name, age
from sashelp.class
where name like 'J%'
;
quit;
ods csv close;
EXPORT Procedure
Where clause can be applied using kept columns of 'a large table' (data=)
proc export
data = sashelp.class(
keep=name age
where = (
name like 'J%'
)
)
replace
file = 'c:\temp\class-subset.csv'
dbms = csv
;
run;
DATA _null_
Where statement can be applied using any columns of 'a large table' (SET). The PUT statement manages which columns are output.
data _null_;
set sashelp.class;
where name like 'J%';
file 'c:\temp\subset-per-datastep.csv' dlm=',' dsd;
if _n_ = 1 then put 'name,age';
put name age;
run;
I think you can use ods to create file with results, for example:
ods csv file="C:\test.csv" options(delimiter=';');
proc sql;
select * from sashelp.class;
quit;
ods csv close;

Exporting data from SAS to Excel with a custom file name

I need to export a data set from SAS to Excel 2013 as a .csv file. However, I need the file name to be dynamic. In this instance, I need it to appear as:
in_C000000_013117_65201.csv
where the string, "in_C000000_" will remain constant, the string "013117_" will be the current day's date, and the string "65201" will be the row count of the data set itself.
Any help that you can provide would be much appreciated!
Thanks!
Here's a modified macro I wrote in the past that does almost exactly what you're asking for. If you want to replace sysdate with a date in your desired format, that's easy to do as well:
%let path = [[desired destination]];
%macro exporter(dataset);
proc sql noprint;
select count(*) into: obs
from &dataset.;
quit;
data temp;
format date mmddyy6.;
date = today();
run;
proc sql noprint;
select date format mmddyy6. into: date_formatted
from temp;
quit;
proc export data = &dataset.
file = "&path.in_C000000_&date_formatted._%sysfunc(compress(&obs.)).csv"
dbms = csv replace;
run;
%mend exporter;
%exporter(your_dataset_here);
Produces datasets in the format: in_C000000_020117_50000.csv

PROC EXPORT outfile row 2

I'm trying to export the column names of a sas data to a xlsx file but need the data to be copied starting in the 2nd row of the excel file. What I have right now:
PROC EXPORT DATA= mylib.test
outfile = "exceltobemodified.xlsx"
dbms = excel replace;
sheet = "test1";
range = "test1$A2:BE2000";
run;
However, I get an error indicating that the RANGE statement is not supported and is ignored in Export procedure
Any suggestions?
Try the data set option FIRSTOBS.
PROC EXPORT DATA= mylib.test (firstobs=2)
outfile = "exceltobemodified.xlsx"
dbms = excel replace;
run;
Edit: If by"starting in the 2nd row" you mean to output the data without the variable names, then you have to use PUTNAMES=NO;
PROC EXPORT DATA= mylib.test
outfile = "exceltobemodified.xlsx"
dbms = excel replace;
PUTNAMES=NO;
run;
Load your table with a blank row as first row. Try writing the table to excel file then. It should work.
Proc sql
insert into test
values('',.,'')
quit;
Proc sort data=test;
by _all_;
run;
Options missing='';
proc export data=test outfile='/home/libname/new.xlsx'
dbms=excel replace;
putnames=no;
run;

SAS proc import .xls with several spreadsheet and append

Situation: i have a workbook .xls with 4 spreadsheets named "SheetA", "SheetB", "SheetC", "SheetD".
For import one spreadsheet i do as following.
proc import
out = outputtableA
datafile = "C:\User\Desktop\excel.xls"
dbms = xls replace;
sheet = 'SheetA';
namerow = 3;
startrow = 5;
run;
All spreadsheet have same number of variables and format. I would like to combine all four outputtableX together using data step:
data combinedata;
set outputtableA outputtableB outputtableC outputtableD;
run;
I am new to SAS, i m thinking whether array and do-loop can help.
I would not use a do loop (as they're almost always overly complicated). Instead, I would make it data driven. I also would use Reese's solution if you can; but if you must use PROC IMPORT due to the namerow/datarow options, this works.
First, create the libname.
libname mylib excel "c:\blah\excelfile.xls";
We won't actually use it, if you prefer the xls options, but this lets us get the sheets.
proc sql;
select cats('%xlsimport(sheet=',substr(memname,1,length(memname)-1),')')
into :importlist separated by ' '
from dictionary.tables
where libname='MYLIB' and substr(memname,length(memname))='$';
quit;
libname mylib clear;
Now we've got a list of macro calls, one per sheet. (A sheet is a dataset but it has a '$' on the end.)
Now we need a macro. Good thing you wrote this already. Let's just substitute a few things in here.
%macro xlsimport(sheet=);
proc import
out = out&sheet.
datafile = "C:\User\Desktop\excel.xls"
dbms = xls replace;
sheet = "&sheet.";
namerow = 3;
startrow = 5;
run;
%mend xlsimport;
And now we call it.
&importlist.
I leave as an exercise for the viewers at home wrapping all of this in another macro that is able to run this given a filename as a macro parameter; once you have done so you have an entire macro that operates with little to no work to import an entire excel libname.
If you an xls file and are using a 32 bit version of SAS something like this would work:
libname inxls excel 'C:\User\Desktop\excel.xls';
proc datasets library=excel;
copy out=work;
run; quit;
libname inxls;
Then you can do your step above to append the files together. I'm not sure Proc Import with excel recognizes the option name row and start row so you may need to modify your code somehow to accommodate that, possibly using firstobs and then renaming the variables manually.
What you have will work assuming the variable names are the same. If they are not use the rename statement to make them all the same.
data combinedata;
set outputtableA(rename=(old_name1=new_name1 old_name2=new_name2 ... ))
outputtableB(...)
...
;
run;
Obviously, fill in the ellipses.