How to open .sas7bdat in SAS and export to excel? - excel

I am quite new to SAS. I have got a file with file extension .sas7bdat which contains daily stocks prices and percentage changes. It has almost 2 million line items. I know that I can simply double click the file and open it with SAS 9.4. But, I am looking for codes which I can type in Editor and open this file. Please help me.
After I open this file, I need to export it to excel. Since it has 2 million data, I can not export everything in a single excel tab. So, What I want to do it randomly pick (say 10,000 or 20,000) data and export only this randomly picked data to excel.
My .sas7bdat file is on desktop.
Please help.

You can use surveyselect and specify the number of records you want in your subset the use proc export.
In my Example below I create a table of 10 rows and only wanted 5 row in the subset. just change the value in my macro variable from 5 to 100000
Code:
data have;
input value;
datalines;
1
2
3
4
5
6
7
8
9
10
;
run;
%let subset=5;
proc surveyselect data=have
method=srs n=&subset. out=want;
run;
Output:
value=1
value=2
value=5
value=6
value=10
Exporting:
proc export data=sashelp.class
outfile='c:\myfiles\want.csv'
dbms=csv
replace;
run;
You can also filter on the data you are exporting, dummy example below:
proc export data=want (where=(value > 100 or location='X'))
outfile='c:\myfiles\want.csv'
dbms=csv
replace;
run;

You can use ODS. This will be simpler, but generate a file which will give warning in opening first time
libname rd_data "<Your Path to dataset>"
data temp;
set rd_data.<dataset name>;
rnd = ranuni(123456);
run;
proc sort data = temp out = temp(drop=rnd);
by rnd;
run;
**** Remember this is .xls file, not .xlsx
ods html file = <xls file path - full path>;
proc print data = temp(obs=1000);
run;
ods html close;
Alternatively, you can use DDE (Dynamic Data Exchange)

First, create a library to point to the location on the file system where the data set resides. This is a pointer (in C terms) to the directory.
libname myData "<path to folder>";
From there you can use a random number and a data step to get N random values. Alternatively, PROC SURVEYSELECT can be used, but you might not have it licensed.
data temp;
set myData.<Data Set Name>;
__rnd = ranuni(1);
run;
proc sort data=temp ;
by __rnd;
run;
data toOutput;
set temp(obs=10000 drop=__rnd);
run;
The last Data Step reads in just the first 10,000 records which you randomized above.
Then you can use PROC EXPORT to export the values.
proc export data=toOutput outfile="c:\temp\output.xlsx" dbms=xlsx replace;
sheet="MyData";
run;
The great thing here is that you can create other sheets in the file with additional exports.
proc export data=toOutput outfile="c:\temp\output.xlsx" dbms=xlsx replace;
sheet="MyData2";
run;
This would allow you to create multiple samples or even export all the data across multiple sheets.

Related

"ALL"-Option for BY (SAS PROC TABULATE)

ODS EXCEL FILE="/mypoath/myfile.xlsx" options(
frozen_headers="3"
sheet_name="#byval1");
PROC TABULATE data=out;
BY byVariable;
CLASS varA varB;
TABLES varA, varB;
RUN;
ODS EXCEL CLOSE;
The code above creates an excel-file with different sheets. There is one sheet for each value of the variable byVariable. Is there a way to create an additional sheet "ALL" which contains the results for all values of the byVariable together? I mean something like "ALL" (used in the TABLES-section). I tried BY ALL byVar already (which doesn't work).
Thanks for help!
The simple answer is NO. If you want all of the data then don't use the BY statement.
ODS EXCEL FILE="/mypoath/myfile.xlsx" options(frozen_headers="3");
ODS EXCEL options(sheet_name="ALL");
PROC TABULATE data=out;
CLASS varA varB;
TABLES varA, varB;
RUN;
ODS EXCEL options(sheet_name="#byval1");
PROC TABULATE data=out;
BY byVariable;
CLASS varA varB;
TABLES varA, varB;
RUN;
ODS EXCEL CLOSE;
There is no such option.
You can:
rerun the report without BY, or
stack the data on itself modifying the by variable to be ALL -- such that it is higher than all existant by values.
data stacked / view=stacked;
set
have
have (in=stackflag)
;
if stackflag then do;
byvar = 'A0'x || 'ALL'; * A0 forces value to be 'after' other original byVar values;
end
run;
proc tabulate data=stacked;
by byvar;
…
Note: 'A0'x is a hard space ASCII character

SAS collapse pivot table column in Excel with DDE

I want to manipulate an existing Excel sheet with DDE using SAS:
I have the following code (be careful! I use z for r(ows) and s for c(columns) because of German language settings in Excel):
option noxwait noxsync;
x call "C:\Program Files (x86)\Microsoft Office\Office15\EXCEL.EXE";
%let delay=5;
data _null_;
rc=sleep(&delay);
run;
filename sas2xl dde 'excel|system';
data _null_;
rc=sleep(&delay);
run;
%let mapwkbk=H:\odstest.xlsx;
data _null_;
file sas2xl;
rc=sleep(&delay);
put '[open("' "&mapwkbk" '")]';
run;
filename random dde 'excel|Daten!z2s1:z100s3';
data _null_;
set sashelp.class;
file random;
put name sex age;
run;
data _null_;
file sas2xl;
/*rc=sleep(&delay);*/
put '[workbook.select("Pivot")]';
put '[select("Z2S1")]';
put "[pivot.refresh()]";
put '[workbook.select("Daten")]';
put '[select("z1S2:z1s5")]';
put '[filter]';
put '[select("z1S10")]';
put '[filter]';
put '[column.width(0,"s1",false,1)]';
put '[column.width(0,"s6:s9",false,1)]';
put '[workbook.delete("Dim")]';
/*put "[save()]";*/
/*put "[quit()]";*/
run;
Now I would like to collapse some columns of the pivot table. How to reach this?

SAS PROC IMPORT with Dynamic Named Ranges

I have a workbook containing database information split into various tabs that I want to import into SAS for further manipulation.
The dimensions of these database tables vary from tab to tab and in addition, there might be further changes to the dimensions of the table throughout the tenure of this project.
As such, I've set up dynamic named ranges in every tab such that it picks up the exact dimensions I require i.e. My named range TBL_SHEET1
=OFFSET(SHEET1!$A$1,0,0,COUNTA(SHEET1!$A:$A),COUNTA(SHEET1!$1:$1)-2)
Now the SAS issue is that when I use the proc import code, it does not seem to think these named ranges "exist" and returns a failure message in the log.
Is there a way around this? Or just a limitation in the way SAS communicates with Excel?
(As a side note, the reason why I am not just importing the entire tab is because there are some extra columns to the right which I want to exclude from my import)
My SAS import code:
proc import
out= rwork.SHEET1
datafile = "C:\My User\Sample.xlsx"
dbms= excel replace;
range=TBL_SHEET1.;
getnames=yes;
run;
Adding your code will really help. However, if I understood your question correct, the problem is with importing named ranges. Here's an example on how to import user defined named range into SAS.
In the example below, I am selecting Range A1:C7 and naming the range as Test
Now, to import the names range Test into SAS,
PROC IMPORT OUT= WANT
DATAFILE= "C:\Desktop\Test.xls"
DBMS=XLS REPLACE;
RANGE="Test";
GETNAMES=YES;
RUN;
In the above code, Range tells SAS to import data from excel under named range Test. You can also automate the code and import multiple excel sheets with dynamic name range into SAS.
For example, I have multiple sheets in an Excel which I want to import into SAS, I'll use the following code to bring the spreadsheets to SAS.
# Assigning Library #
Libname Test "C:\Desktop\Test.xls";
# Creating a table to select sheet names in above library #
Proc sql;
create table test_excel as
select *
from dictionary.tables
where libname="Test" ;
Quit;
# Assigning count and Sheet names to macros#
## Sheet names ##
Proc sql;
select memname into: list seperated by '*'
from test_excel
;
quit;
## Number of sheets ##
Proc sql;
select count(memname) into:count
from test_excel
;
quit;
# Macro to import #
options mprint;
%macro import;
%do i=1 %to &count;
%let var=%scan(&list,&i,*);
PROC IMPORT OUT= %substr(&var,1,%length(&var)-1)
DATAFILE= "C:\Desktop\Test.xls"
DBMS=EXCEL REPLACE;
RANGE="&var";
GETNAMES=YES;
RUN;
%end;
%mend import;
%import ;
I hope this is clear.
I replicated the problem and also can't import a dynamic (not fixed) range from Excel. It doesn't work on either EXCEL or XLSX engines.
If you need a quick solution and don't necessarily have to use Excel ranges, here is a workaround for the problem:
Allocate one sheet's cell, e.g A1 for storing what you currently store in the dynamic range TBL_sheet1, i.e. the range of cells to import.
Execute proc import only to import this range of cells:
PROC IMPORT DATAFILE="C:\test.xlsx" DBMS=xlsx out=work.x
replace;
getnames=no;
RANGE="Sheet1$A1:A1";
RUN;
Next, put the imported range to a macro variable and execute proc import again with proper RANGE= definition.
%let range=;
proc sql noprint;
select A into :range
from work.x;
quit;
%let range = %sysfunc(compress(&range.,$,));
%put &range.;
/* resolves to: B2:B4 */
%macro import(x);
PROC IMPORT DATAFILE="C:\test.xlsx" DBMS=xlsx out=work.y
replace;
getnames=no;
RANGE="Sheet1$&x.";
RUN;
%mend;
%import(&range.);

SAS- Defining Page Breaks inside Macro

I am wondering if there is a way of defining when and where page breaks occur when using a macro to output data. I know within the various ODS tagests the "Startpage=NOW" can be used but that does not seem to work if a macro is used inside that tagset. So basically I want the two tables, and graph for each personal ID code to be on a single and the next page contains the same summary graphs, charts for that individual, and etc. Currently I can only get every table and chart to its own individual page which makes for a lengthy report! Any help/suggestions would be appreciated!
/*************************************************************************/
/* Create a macro variable of all the ID codes */
/* */
/*************************************************************************/
proc sql noprint;
select personal_id
into :varlist separated by ' ' /*Each identifier code in the list is sep. by a single space*/
from provider;
quit;
%let cntlist = &sqlobs; /*Store a count of the number of id codes*/
%put &varlist; /*Print the codes to the log to be sure our list is accurate*/
ods tagsets.rtf file="C:\USER\test.doc" style=sasdocprinter;
/* macro for generating the output table*/
%macro output(x);
proc print data=prov_&x;
run;
proc print data=prov_revCD_&x;
run;
/*Print graph to template defined earlier*/
ods graphics on / height=500px width=500px;
proc sgrender data=summary_&x template=corf_graphs;
run;
ods graphics on / reset=all;
%mend;
%macro loopit(mylist);
%let else=;
%let n = %sysfunc(countw(&mylist)); /*let n=number of codes in the list*/
data
%do I=0 %to &n;
%let val = %scan(&mylist,&I); /*Let val= the ith code in the list*/
%end;
/*Run a loop for each oscar code. Each code will enter the
%do j=0 %to &n;
%let val = %scan(&mylist,&j); /*Let val= the jth code in the list*/
/*Run the macro loop to generate the required tables*/
%runtab(&val);
%output(&val);
%end;
run;
%mend;
%loopit(&varlist)
/*Run the macro loop over the list of significant procedure code values*/
ods tagsets.rtf close;
Macros are nothing but source code generation devices. They have no impact on the effectiveness of any particular technique, except insomuch as their (mis)use may make it more difficult to see how to do it properly.
In this case, if you want the entirety of each single iteration of %output() to be on one page, then you simply need to add a startpage now before the %output(&val) call.
%runtab(&val);
ods tagsets.rtf startpage=now;
%output(&val);
%end;
That will produce a startpage instruction immediately before the output. You could just as easily include it in the %output macro, if you will always want a new page before a call of it.
I inserted the startpage=NOW where suggested and it inserted a blank page, after playing around with the placement and looking at what the code is doing this following snip it ended up working:
ods tagsets.rtf startpage=NOW;
%runtab(&val);
%output(&val);
ods tagsets.rtf startpage=no;
%end;
Beyond the use of macro, you can also consider the use of pagebywith proc print to split page for you.
See this link for PageBY

Exporting multiple sas datasets into multiple excel sheets with macro?

I am looking if there is a macro that would export multiple datasets into separate excel worksheets within a workbook. Would be great if I could have 10 sheets per workbook.
I can do it the usual way as below, but I have more than 100 datasets to export:
PROC EXPORT DATA=HAVE;
OUTFILE= "S:\MYEXCEL.xlsx"
DBMS=EXCEL REPLACE;
SHEET="NEW_SHEET";
RUN;
Thank you!
The general concept is that you would do something like this:
%macro export_data(file=,data=,sheet=);
proc export data=&data.
outfile="&file."
dbms=excel replace;
sheet="&sheet.";
run;
%mend export_data;
Then you need to construct your export macro calls however you want. Get a dataset with one row per dataset (use dictionary.tables in SQL or sashelp.vtable in data step) and work out however you want to the logic of the sheet names and how many workbooks you need. Google data-driven macro calls for more information.
Provided you have 'SAS/Access to PC FIle formats' licensed, this little macro does it effortlessly:
%macro SASToExcel(ImportLibrary=, ExportLocation=);
ods output members = _Members;
proc datasets lib = &ImportLibrary; run; quit;
proc sql;
select count(Name) into :NumOfDatasets from _Members;
select Name into :Dataset1-:Dataset%trim(%left(&NumOfDatasets)) from _Members;
quit;
%do index = 1 %to &NumOfDatasets;
proc export data=&ImportLibrary..&&Dataset&index.
outfile="&ExportLocation"
dbms=excel replace;
sheet="&&Dataset&index";
run;
%end;
proc datasets;
delete _Members;
quit;
%mend;
%SASToExcel(ImportLibrary=raw, ExportLocation = c:\test.xlsx);

Resources