当前位置: 首页 > 知识库问答 >
问题:

在sas中编写vba代码

仲孙华奥
2023-03-14

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

我刚刚意识到我不能以启用宏的Excel格式XLSM导出SAS中的表。我想这也是一个挑战。此外,从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;

共有3个答案

吕灿
2023-03-14

使用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;
通鸿风
2023-03-14

我总是发现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;
柴翰藻
2023-03-14

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

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

这使您可以运行所有内容,而无需以任何方式与之交互——您不必向其中添加新宏或任何内容,因为模板宏已经存在。通过这种方式,一切都可以一次性完成。

例如,在使用SAS®DDE创建基于来自SAS数据集的N个观察值的Excel图的分步中,以及其他一些关于该主题的论文中显示了这一点。

 类似资料:
  • 问题内容: 编辑:这是一组更完整的代码,确切显示了下面每个答案所发生的事情。 目的是仅根据类别成员资格在表中查询一些ID。然后,我总结了这些成员在所有类别中的活动。 上面的方法比以下方法慢得多: 运行第一个查询以获取子集 运行第二个查询求和每个ID 运行内部连接第三个结果集的第三个查询。 如果我理解正确,那么确保完全通过我的所有代码而不是交叉加载可能会更有效率。 在昨天发表问题后,一位成员建议我从

  • 了解如何在“代码”视图中工作并充分利用 Dreamweaver 的编码功能。 可通过多种方式在 Dreamweaver 中处理代码。 您可以使用“新建文档”对话框打开新的代码文件,然后开始键入您的代码。在 Dreamweaver 中创建新的代码文件 键入时,会显示代码提示以帮助您选择代码和避免打字错误。如果需要,可使用 Dreamweaver 的有用的快捷文档获取 CSS 的相关帮助。 还可以使用

  • 11.3 编写代码 要完成我们的程序,我们需要创建一个Java文件。默认情况下,Maven会编译src/main/java目录下的源文件,因此您需要创建该目录结构,然后添加一个名为src/main/java/Example.java的文件: import org.springframework.boot.*; import org.springframework.boot.autoconfigur

  • /*我们使用Aspect在一些现有的应用程序上进行AOP,我们还使用threadlocal来存储GUId。我们使用@Around注释。在事务开始时,我们用initialValue()方法设置事务中的GUID。 问题是,当我们使用threadlocal时,我们还应该注意从threadlocale中删除数据,否则可能会导致内存执行失败。如果我在方面的最后删除它,它会破坏代码并更改UUID值。 请建议我

  • 问题内容: 我可以很轻松地在Node.js中编写非阻塞I / O。 这就是整个库的用途。 但是所做的任何计算都是阻塞的。任何通过事件发送器的消息都将被阻止。 例如,发出事件立即得到解决,因此被阻止: 除了将调用包装起来外,如何使代码无阻塞? 我希望在事件循环的每个周期中进行尽可能少的计算,以便可以同时为尽可能多的客户端提供服务。 如何以非阻塞方式编写代码? 当我拥有非阻塞代码时,如何在多个进程之间

  • 问题内容: 我想评估 作为一个块,而不是逐行评估 有没有简单的方法可以将提示移至下一行? 问题答案: 节点v6.4具有一种模式。在repl提示符下,您可以输入多行。 例 以下是所有特殊repl命令的文档 https://nodejs.org/api/repl.html#repl_commands_and_special_keys