How to make cell range dynamic in DDE in SAS - excel

I am trying to format a weekly report using DDE in sas which opens a excel file kept on my desktop location. I want to format the font some of these cells. I have a total column which needs to be formatted every time the new data comes in. But every time this data would come out the range of the "Total" cell would be different. Please refer to the code i am writing
options noxsync noxwait;
filename sas2xl dde 'excel|system';
data _null_;
length fid rc start stop time 8;
fid=fopen('sas2xl','s');
if (fid le 0) then do;
rc=system('start excel');
start=datetime();
stop=start+10;
do while (fid le 0);
fid=fopen('sas2xl','s');
time=datetime();
if (time ge stop) then fid=1;
end;
end;
rc=fclose(fid);
run;
data _null_;
file sas2xl;
put '[open(myfilepath\file.xlsx")]';
run;
**I had created a macro using call symput and i am using it here for dynamically changing the row number**
%macro xyz;
data _null_;
file sas2xl;
%do i= 1 %to 3;
put '[error(false)]';
put '[workbook.activate("Sheet1")]';
put '[select("r&&rownum&i..c1")]';
put '[format.font("Arial",true,false,false,false,1,false,false)]';
put '[column.width(0,"c1:c6",false,3)]';
%end;
run;
ERROR
The code is not working and give me a error like this
DDE session not ready. FATAL:
Unrecoverable I/O error detected in the execution of the DATA step program. Aborted during the EXECUTION phase.
Can you please tell me how can i go ahead in this

Related

Error in proc export - Cannot delete worksheet cells

Iam using a proc export step to replace a sheet in my spreedsheet with new data.
PROC EXPORT data = work.filtro_segmentos2
outfile = "myfolder/BASE_DIAG.done.xlsx"
dbms = EXCELCS replace;
sheet = "ANALÍTICO";
SERVER = "&IP_ADDRESS.";
PORT = &PORTA.;
RUN;
but this error keeps happening:
ERROR: CLI execute error: [Microsoft][Driver ODBC Excel] Cannot delete worksheet cells.
WARNING: Table _IMEX_."ANALÍTICO$" has not been dropped.
ERROR: There was a problem removing the original table ANALÍTICO. See Log for details.
I've done some research in SaS documentation and find this solution, but I dont know how to adapt to my needs(replace a whole sheet). A little experience as help would be great!
The first example sends data from a SAS session to an Excel spreadsheet. The target cells are rows 1 through 100 and columns 1 through 3. To send the data, submit the following program:
/* The DDE link is established using */
/* Microsoft Excel SHEET1, rows 1 */
/* through 100 and columns 1 through 3 */
filename random dde
'excel|sheet1!r1c1:r100c3';
data random;
file random;
do i=1 to 100;
x=ranuni(i);
y=10+x;
z=x-10;
put x y z;
end;
run;
SaS Documentation
Thanks!

How to make PC SAS DDE Sever Code to communicate with Windows 10 Excel 2016

I had set up a code in PC SAS in my Windows 7 having Excel 2010 and PC SAS 9.4. Basically what the code did was take the dataset 'wide2' and paste it to the only excel file which is open in the OS at that moment and then save it. Following is the code which I was using:
%macro paste(number);
proc print data=wide2;
run;
PROC CONTENTS DATA=wide2 /*NOPRINT*/ OUT=CNT ;
RUN;
PROC SORT DATA=CNT ;
BY VARNUM ;
RUN;
PROC SQL /*NOPRINT*/;
SELECT NAME
INTO: VARS SEPARATED BY ' '
FROM CNT ;
SELECT COUNT(DISTINCT NAME)
INTO: COLS SEPARATED BY ' '
FROM CNT ;
SELECT NOBS
INTO: ROWS
FROM CNT
WHERE VARNUM = 1;
QUIT;
proc print data=cnt;run;
FILENAME TEMP DDE "EXCEL|Sheet&number.!R1C1:R200C200" ;
data _null_ ;
file temp ;
if _n_=1 then do;
do _n_=1 to &cols ;
set cnt(keep=name rename=(name=__name__)) ;
put __name__ #;
end;
put;
end;
set wide2 ;
put &vars ;
run ;
%mend paste;
So when I executed a macro like %paste(1), it would paste the data to Excel's Sheet1.
Now we have moved to Windows 10 which has the same PC SAS version but Excel 2016.
When I run the same code with the same dataset, the PC SAS gets hung for an eternity after a couple of seconds and then I have to just kill the process. Nothing happens to the open excel file. I can't even see the log since the PC SAS gets hung. Please suggest a solution for this.( The top bar of the PCSAS when it gets hung says 'running DATA Step')
How many columns and rows in the wide2 data set ? Your posted code ran on my system with SAS 9.4M4 and Office 365. I used this data set.
data wide2;
do id=1 to 3;
array x(15) (1:15);
output;
end;
format _numeric_ 2.;
run;

How to open .sas7bdat in SAS and export to 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.

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- 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

Resources