SAS中动态sql查询的宏变量参考

时间:2016-10-24 10:36:49

标签: sas sas-macro

我使用SAS宏变量来存储2个sql查询(2个宏),以便进行动态执行。区别在于一个是SAS SQL的查询字符串,另一个是MS SQL的查询字符串,它将通过传递工具执行.2个查询的组成非常相似。我利用%STR和%NRSTR来形成查询字符串,并将它们存储到宏变量中。以下是书面宏功能的全部内容:

%LET initialDate=19Oct2016;
%LET lastDate=19Oct2016;
%MACRO compressDataSetFirstTime(table, library=ANY);
PROC SQL NOPRINT;
    /*Get the character variables*/
    SELECT name, varnum INTO :characterVariableList SEPARATED BY ', ' 
     FROM DICTIONARY.COLUMNS
     WHERE libname="&library" AND memname="&table" AND type='char'
     ORDER BY varnum;
    /*Get the numeric variables*/
    SELECT name, varnum, type INTO :numericVariableList SEPARATED BY ', ' 
     FROM DICTIONARY.COLUMNS
     WHERE libname="&library" AND memname="&table" AND type='num'
     ORDER BY varnum;

%PUT 文字變數清單:&characterVariableList;
%LET characterVariableList=(&characterVariableList);
%LET numericVariableList=%STR(&numericVariableList, );
%PUT 數值變數清單:&numericVariableList;
%LET queryString=%STR(SELECT ); %LET macroClause=%STR( INTO ); 
%LET queryMSSQL=%STR(SELECT )&numericVariableList;
%LET listNumber=%SYSFUNC(COMPRESS(%EVAL(%SYSFUNC(COUNT(&characterVariableList, %STR(,)))+1)));
%PUT 共有&listNumber.個文字型態變數。;
/*Compose the query for macro and the mssql query.*/
%DO variableNumber=1 %TO &listNumber;
    %IF &variableNumber LT &listNumber %THEN %DO;
        %LET variableName=MAX(LENGTH(STRIP(%SCAN(&characterVariableList, &variableNumber)))),;
        %LET queryString=&queryString&variableName;
        %LET macroClause=&macroClause%STR(:variable&variableNumber, );
        %LET variableNameMSSQL=SUBSTRING(%SCAN(&characterVariableList, &variableNumber), 1, %NRSTR(%SYSFUNC%(COMPRESS%(&)variable&variableNumber))) AS %SCAN(&characterVariableList, &variableNumber),%STR( );
        %LET queryMSSQL=&queryMSSQL&variableNameMSSQL;
    %END;
    %ELSE %DO;
        %LET variableName=MAX(LENGTH(STRIP(%SCAN(&characterVariableList, &variableNumber))));
        %LET queryString=&queryString&variableName;
        %LET macroClause=&macroClause%STR(:variable&variableNumber);
        %LET variableNameMSSQL=SUBSTRING(%SCAN(&characterVariableList, &variableNumber), 1, %NRSTR(%SYSFUNC%(COMPRESS%(&)variable&variableNumber))) AS %SCAN(&characterVariableList, &variableNumber);
        %LET queryMSSQL=&queryMSSQL&variableNameMSSQL;
    %END;
%END;
%LET queryString = &queryString&macroClause%STR( FROM &library..&table WHERE dates BETWEEN "&initialDate"D AND "&lastDate"D;);
%LET queryMSSQL = &queryMSSQL%STR( FROM dbo.&table WHERE dates BETWEEN %NRSTR("%SYSFUNC(PUTN("&initialDate"D, YYMMDD10.))") AND %NRSTR("%SYSFUNC(PUTN("&lastDate"D, YYMMDD10.))"););
%PUT The query string with macro clause:&queryString;
/*Execute the query for macro*/
    &queryString
/*
    This is for examination.
%DO checkNumber=1 %TO &listNumber;
    %PUT variable&checkNumber.接受到的長度:%SYSFUNC(TRIM(&&variable&checkNumber));
%END;*/
%PUT 遞過功能MSSQL查詢語句:&queryMSSQL;
/*Execute the mssql query with the pass-through facility*/
    CONNECT TO SQLSVR AS sjconn
        (DATABASE="***" USER=*** PASSWORD=***);
        CREATE TABLE Desirable_Result AS
        SELECT *
        FROM connection to sjconn
        ( 
            /* The printed result of queryMSSQL from log using %PUT. */
            /* &queryMSSQL */
        );
        DISCONNECT FROM sjconn;
QUIT;
%MEND;

我遇到的问题是存储在宏变量中的查询无法在带有传递工具的PROC SQL中执行。

第二个查询由MSSQL中的SUBSTRING函数,%SYSFUNC和一些宏变量组成,如下所示:%PUT:

SELECT SUBSTRING(var, 1, %SYSFUNC(COMPRESS(&len_var))) AS var
FROM table 
WHERE date BETWEEN "%SYSFUNC(PUTN("&firstdate"D, YYMMDD10.))" AND 
"%SYSFUNC(PUTN("&lastdate"D, YYMMDD10.))";

假设& query存储查询字符串,我的问题是如果我在日志中使用打印结果并将其放在带有传递工具的PROC SQL中,它可以工作,但如果我使用& query并将其放入使用传递工具的PROC SQL失败了。

简而言之,

此作品

CONNECT TO SQLSVR AS conn (related setting);
CREATE TABLE TMP AS
SELECT *
FROM connection to conn
(
     /* The following query is the result I coped from the log where I used %PUT to print <br> the content of &query */
   SELECT SUBSTRING(var, 1, %SYSFUNC( COMPRESS(&len_var))) AS var
   FROM table 
   WHERE date BETWEEN "%SYSFUNC(PUTN("&firstdate"D, YYMMDD10.))" AND    "%SYSFUNC(PUTN("&lastdate"D, YYMMDD10.))";
);

此操作失败

CONNECT TO SQLSVR AS conn (*related setting*);
CREATE TABLE TMP AS 
SELECT * 
FROM connection to conn
(
     &query
);

日志中的错误消息显示'SYSFUNC'附近的语法不正确。

有什么理由呢?

1 个答案:

答案 0 :(得分:3)

不幸的是,您无法以这种方式使用%SYSFUNC%SYSFUNC(如果由于拼写错误而未将其保留,则需要%)必须执行系统功能;你在这里没有要求它。你的&#34;这适用于&#34;事实上,它不起作用,或者至少不应该起作用,并且可能不会做你期望它做的事情,如果它实际上会返回一些东西(这会让我感到非常惊讶)。 / p>

例如,这个最简单的事情:

%let x = %SYSFUNC("&firstdate"D, YYMMDD10.);

失败并显示错误:

ERROR: Function name missing in %SYSFUNC or %QSYSFUNC macro function reference.

那么,我们如何解决这个问题呢?相当简单,使用简单的函数putn。事实上,你可以将它包装在你现在拥有的东西之外,它将直接起作用。

%let firstdate=01JAN2015;
%let x = %SYSFUNC(putn("&firstdate"D, YYMMDD10.));
%put &=x;

至于为什么它似乎对你有用,如果你以第一种方式运行它而不是第二种方式...谁知道。如果它确实以第一种方式工作(如果你不准确地转录了这个例子),那么我的建议是你已经用宏引用做了一些事情,SQL编译器并不愿意去做。 %unquote当你使用它时,作为第一步找出它,或者改变你引用它的方式并不是一个坏主意(使用%str而不是%nrstr或使用{{1}而不是%bquote等),看看哪些有效,哪些无效。在宏引用方面,%str是众所周知的挑剔,而数据步骤将很快自动取消引用SQL的事情总是不会。