我想将我的VBA代码实现到我的SAS代码中,因此我可以通过一次运行完成整个过程。我的SAS代码读取一个大的SAS表,进行一些转换,最后导出到Excel文件(代码如下)。我还在Excel文件中写了一些VBA代码(例如,对于某些变量,可以看到自动筛选,您可以看到下面的代码)。
表格如下:
A B C Var1 Var2 Var3
--------------------
1 1 1 10 15 20
1 1 2 15 20 30
1 2 1 20 30 40
1 2 2 30 40 50
2 1 1 40 50 60
2 1 2 50 60 70
2 2 1 60 70 80
..............
..............
然而,我想将我的VBA代码实现到我的SAS代码中,所以我可以通过一次运行完成整个过程。我知道如何在SAS中打开并运行Excel文件(代码在下面),但我不知道如何在我的SAS中实现VBA代码。
如果你想知道我为什么要在我的SAS中实现我的宏代码,我将来会多次使用类似的SAS表,所以将整个代码放在一个地方会更实际。< / p>
我刚刚意识到我无法以支持宏的Excel格式XLSM导出SAS中的表格。我想这也是一个挑战。此外,从Excel文件中保存宏代码并不是那么实际,因为它必须保存在“添加”菜单中。因此,在一个地方处理整个过程会更好,就像在SAS编辑器中一样。
SAS中将最终表导出到Excel文件的代码:
PROC EXPORT DATA=File1
OUTFILE= "&server\&env\test1.xlsx"
DBMS=EXCEL REPLACE;
SHEET="sheet1";
RUN;
Excel文件中的VBA代码示例,用于为Excel文件中的变量创建AutoFilter:
Sub Macro1()
Dim N As Long, r As Range
With Sheets("sheet1")
N = .Cells(Rows.Count, "B").End(xlUp).Row
ReDim ary(1 To N)
For i = 1 To N
ary(i) = .Cells(i, 1)
Next i
End With
Range("A1:F20").AutoFilter
ActiveSheet.Range("$A$1:$F$20").AutoFilter Field:=1, Criteria1:=ary, Operator:=xlFilterValues
End Sub
SAS中用于在SAS中启动和运行Excel文件的代码:
OPTIONS NOXWAIT NOXSYNC;
DATA _NULL_;
RC=SYSTEM('START EXCEL');
RC=SLEEP(0.5);
RUN;
FILENAME CMDS DDE 'EXCEL|SYSTEM';
DATA _NULL_;
FILE CMDS;
PUT "[OPEN(""&server\&env\test1.XLS"")]";
PUT '[RUN("Macro1")]';
PUT '[SAVE.AS("&server\&env\FORMATTED_FILE.XLSM")';
PUT "[QUIT()]";
RUN;
QUIT;
答案 0 :(得分:2)
执行此操作的常用方法是使用模板文件。你保存了你的模板,其中保存了excel宏(也许还有一些格式化;使用DDE,毕竟你不必从一个空白的工作表开始)。
您可以使用DDE填充模板工作簿/工作表,然后使用&#34;另存为&#34;另一个文件,或者您可以使用DDE创建新的工作簿和工作表,打开模板工作簿,运行宏,关闭模板。您所做的可能取决于您是否要将宏与结果一起分发。
这允许您以任何方式运行所有内容而无需与其进行交互 - 您不必向其添加新宏或任何内容,因为模板宏已经存在。一切都可以通过这种方式完成。
例如在论文Step-by-Step in Using SAS® DDE to Create an Excel Graph Based on N Observations from a SAS Data Set中以及关于该主题的其他几篇论文中显示了这一点。
答案 1 :(得分:1)
I've always found DDE to be a bit clunky and it gets upset if you touch the excel workbook while its running. This example writes a VBscript to sas workspace then executes iut. Basically you can get the put statements to write code for whatever you want the program to do and it can be driven by whats in a SAS dataset. This example adds a header and foter to an existing excel spreadsheet...
%macro xlHeadFoot(WorkBookPath=,Header=FileName,Footer=SheetName,onlySheet=);
%local _shortpath WorkBook;
data _null_;
length header footer $200;
header=ifc(lowcase("&header.")='filename' or lowcase("&header.")='sheetname',tranwrd(tranwrd(lowcase("&header."),'filename','&F'),'sheetname','&A'),"&header.");
footer=ifc(lowcase("&footer.")='filename' or lowcase("&footer.")='sheetname',tranwrd(tranwrd(lowcase("&footer."),'filename','&F'),'sheetname','&A'),"&footer.");
call symput("header",trim(header));
call symput("footer",trim(footer));
run;
%let WorkBook=%scan(&WorkBookPath.,%sysfunc(countw(&WorkBookPath.,\)),\);
%* ***********************************************;
%* get the short DOS name for the workspace folder;
data _null_;
rc=filename("inpipe",catx('"','for %I in (',"%sysfunc(pathname(work))",') do echo %~sI'),"pipe");
run;
data _null_;
infile inpipe truncover end=last;
input @1 data $256. ;
rc=filename("inpipe","");
if last then call symput('_shortpath',trim(data));
run;
%* *******************************;
%* tidy up any previous executions;
data _null_;
if fileexist("&_shortpath\testx.vbs") then do;
rc=filename("dump","&_shortpath\testx.vbs");
rc=fdelete('dump');
msg=sysmsg();
if msg ne '' then put msg=;
end;
if fileexist("&_shortpath\xmlFile.xml") then do;
rc=filename("dump","");
rc=filename("dump","&_shortpath\xmlFile.xml");
rc=fdelete('dump');
msg=sysmsg();
if msg ne '' then put msg=;
rc=filename("dump","");
end;
run;
%if %sysfunc(fileexist("&WorkBookPath."))=1 %then %do;
data null;
file "%sysfunc(pathname(work))\testx.vbs";
put @1 'Set objExcel = CreateObject("Excel.Application")';
put @1 'objExcel.Application.Visible = True';
put @1 'objExcel.Workbooks.open "' "&WorkBookPath." '"' ;
%if %str(&onlySheet.) ne %str() %then %do;
put @1 'onlySheetExisits=False';
put @1 'for each sheet in objExcel.Workbooks("' "&WorkBook." '").sheets';
put @1 'if strcomp(sheet.name,"' "&onlySheet." '",1)=0 then onlySheetExisits=True';
put @1 'if strcomp(sheet.name,"' "&onlySheet." '",1)=0 then sheet.PageSetup.CenterHeader = "' "%str(&Header.)" '"';
put @1 'if strcomp(sheet.name,"' "&onlySheet." '",1)=0 then sheet.PageSetup.CenterFooter = "' "%str(&Footer.)" '"';
put @1 'Next';
%end;
%else %do;
put @1 'for each sheet in objExcel.Workbooks("' "&WorkBook." '").sheets';
put @1 'sheet.PageSetup.CenterHeader = "' "%str(&Header.)" '"';
put @1 'sheet.PageSetup.CenterFooter = "' "%str(&Footer.)" '"';
put @1 'Next';
%end;
put @1 'objExcel.Workbooks("' "&WorkBook." '").save';
put @1 'objExcel.Workbooks("' "&WorkBook." '").Close';
put @1 'objExcel.Application.Quit';
%if %str(&onlySheet.) ne %str() %then %do;
put @1 'if onlySheetExisits=False then msgbox "Error! Could not find Worksheet: '"&onlySheet."' in Workbook: "' ' & vbcr & ' '" '"&WorkBookPath." '",16,"SAS: '"&SYSMACRONAME"'"';
%end;
run;
x %sysfunc(quote("&_shortpath.\testx.vbs"));
%end;
%else %put %str(ERR)OR: [&SYSMACRONAME.] Unable to open: &WorkBookPath. - check it exists!;
%mend;
答案 2 :(得分:0)
使用DDE,您可以在SAS中设置过滤器:
data _null_;
FILE CMDS;
/* select your worksheet */
put '[workbook.select("your_sheet")]';
/* select the column range you want to set the filter */
put '[select("r1c2:r1c5")]';
/* set filter */
put '[filter]';
run;