【问题标题】:Writing vba code in sas用sas写vba代码
【发布时间】:2015-09-13 13:53:15
【问题描述】:

我想将我的 VBA 代码实现到我的 SAS 代码中,这样我可以一次运行完成整个过程。我的 SAS 代码读取一个大 SAS 表,进行一些转换,最后导出到 Excel 文件(代码如下)。我还在 Excel 文件中写了一些 VBA 代码(例如 AutoFiltering for some variables,你可以看下面的代码)。

表格如下所示:

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 表,因此将整个代码保存在一个地方会更实用。

我刚刚意识到我无法在 SAS 中以启用宏的 Excel 格式 XLSM 导出表格。我想这也是一个挑战。此外,从 Excel 文件中保存宏代码也不是很实用,因为它必须保存在 Adds-in 菜单中。所以最好在一个地方处理整个过程,比如在 SAS 编辑器中。

SAS 中将最终表格导出到 Excel 文件的代码:

PROC EXPORT DATA=File1
        OUTFILE= "&server\&env\test1.xlsx" 
        DBMS=EXCEL REPLACE; 
   SHEET="sheet1"; 
RUN;

Excel 文件中用于为 Excel 文件中的变量创建自动筛选的 VBA 代码示例:

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;

【问题讨论】:

  • 您是说您希望能够通过 DDE 创建一个新的 Excel 文件,然后通过 SAS 以编程方式在其中创建一个新的 VBA 宏?
  • 基本上,是的。我希望我的 SAS 代码能够读取 SAS 表,将结果导出到 Excel 文件(如果可能,请使用 XLSM),并且我的 SAS 代码还将运行一些 VBA 代码以使 Excel 文件更美观。我希望所有这些进程都只在一个代码中运行一次......
  • 你运行的excel宏总是一样的吗?使用excel模板的方法会起作用吗?我认为这是执行此操作的标准方法;您将 excel 宏存储在静态的“模板”工作簿中,然后从那里执行它(同时写入不同的工作簿,或者您可以写入模板工作簿,然后另存为不同的工作簿名称)。
  • 我计划将 SAS 中的 VBA 用于相同的表变量,但每个 excel 文件中的数据都会发生变化。我只会在 SAS 文件开头使用 %let var1=&var 更改“宏变量”。您的意思是将 Excel 宏保存为静态模板工作簿,您的意思是 XLSB 格式?你的意思是我只是简单地将我的宏代码保存在任何模板中,然后在需要时复制粘贴它?
  • 如果你的例子是自动过滤器,我认为标签集已经提供了一个很好的机制来做到这一点。此外,您可以导出到 XLSM,我可能已经做过很多次了。你有什么版本的 SAS?

标签: vba excel sas sas-macro


【解决方案1】:

执行此操作的常用方法是使用模板文件。您保存了模板,其中保存了 excel 宏(可能还对其进行了一些格式化;毕竟,使用 DDE 您不必从空白工作表开始)。

您可以使用 DDE 填充模板工作簿/工作表,然后“另存为”另一个文件,或者您可以使用 DDE 创建新的工作簿和工作表,打开模板工作簿,运行宏,关闭模板.您执行的操作可能取决于您是否希望将宏与结果一起分发。

这允许您在不以任何方式与其交互的情况下运行所有​​内容 - 您不必向其添加新宏或任何内容,因为模板宏已经存在。通过这种方式,所有事情都可以一次完成。

这在论文Step-by-Step in Using SAS® DDE to Create an Excel Graph Based on N Observations from a SAS Data Set 以及其他几篇关于该主题的论文中都有展示。

【讨论】:

    【解决方案2】:

    我一直觉得 DDE 有点笨拙,如果在运行时触摸 Excel 工作簿,它会感到不安。此示例将 VBscript 写入 sas 工作区,然后执行 iut。基本上,您可以让 put 语句为您希望程序执行的任何操作编写代码,并且它可以由 SAS 数据集中的内容驱动。此示例将页眉和页脚添加到现有的 Excel 电子表格...

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

    【讨论】:

      【解决方案3】:

      使用 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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-08-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-16
        • 2018-02-11
        • 1970-01-01
        相关资源
        最近更新 更多