【问题标题】:SQL- sequential month macro with multiple loopsSQL-具有多个循环的顺序月份宏
【发布时间】:2017-12-12 17:12:04
【问题描述】:

我正在尝试将连续下降的 12 个月数据合并到一个表中。每月数据联接将查看下降序列。但是,我正在努力想出一个逻辑来开发多个宏来运行它。 月份的格式为 YYYYMM。

代码 `

    PROC SQL;
       CREATE TABLE WANT_YYYYMM AS /* I want the tables on monthly but incremental sequence basis. 
For e.g monthly data for 201612 will join with 201701,201702....201711....
monthly data for 201701 will join with 201702,201703....201711 and so on.*/
       SELECT (COUNT(A.canc_accts)) AS canc_accts_n, 
              (COUNT(A.canc_accts)) AS canc_accts_n+1,
              (COUNT(A.canc_accts)) AS canc_accts_n+2,
              ........
              (COUNT(A.canc_accts)) AS canc_accts_n+11          

    FROM HAVEDATA_YYYYMM A
     LEFT JOIN HAVE_DATA_YYYYMM+1 B ON (A.ACCT_NO= B.ACCT_NO)
     LEFT JOIN HAVE_DATA_YYYYMM+2 C ON (A.ACCT_NO= B.ACCT_NO)
     LEFT JOIN HAVE_DATA_YYYYMM+3 D ON (A.ACCT_NO= B.ACCT_NO)
     ........
     LEFT JOIN HAVE_DATA_YYYYMM+11 G ON (A.ACCT_NO= B.ACCT_NO)
     GROUP BY A.Fees;
    QUIT;

` 表 YYYYMMM 的数据应如下所示

            canc_n   canc_n+1  canc_n+2......  canc_n+10  canc_n+11

201612        200     225       250               325       350
201701        222     240       277               312        -
201702        210     232       234                 -
.
.
201711        200      -         -

在运行月份的宏循环和 canc_n 变量时需要一些帮助。任何帮助构建多个宏或构建它的任何逻辑将不胜感激。

【问题讨论】:

  • 为什么是 SQL 而不是数据步骤?
  • 你为什么要计算同样的东西?那应该是 COUNT(B....) , COUNT(C....) 吗?
  • 您真的有多个以不同 YYYYMM 后缀命名的数据集吗?或者 YYYYMM 的一个数据集中是否有一个字段。希望后者与前者一样,SQL 作为一种声明性语言无法确定标识符名称的逻辑,例如表名,仅包含字段内的数据。
  • 我不明白。你有一张表 HAVE_DATA_YYYYMM?它有一个月份列,它是一个格式为“YYYYMM”的字符串?还有一列acct_no?两列一起是表的主键吗?还有第三列 canc_accts 持有一个值?并且您想在网格中显示数据,每个开始月份有一行,列表示开始月份到开始月份 + 11?显示的值是每月 canc_accts 的总和?那么 201612 的 canc_n+1 是否应该与 201701 的 canc_n 相同,因为两者都是 2017 年 1 月的总和?

标签: sql macros sas


【解决方案1】:

用宏应该很容易做到。为了更轻松地生成类似字符串的日期,您可以使用日期操作函数,例如 intnx()

%macro codegen(yymm);
%local month i ;
%let month=%sysfunc(inputn(&yymm.01,yymmdd8));
PROC SQL;
CREATE TABLE WANT_%sysfunc(intnx(month,&month,0),yymmn6) AS 
  SELECT COUNT(A.canc_accts) AS canc_accts_0
%do i=1 %to 12 ;
   ,COUNT(x&i..canc_accts) AS canc_accts_&i
%end;
  FROM HAVE_DATA_%sysfunc(intnx(month,&month,0),yymmn6) A
%do i=1 %to 12 ;
  LEFT JOIN HAVE_DATA_%sysfunc(intnx(month,&month,&i),yymmn6) x&i
    ON (A.ACCT_NO= x&i..ACCT_NO)
%end;
  GROUP BY A.Fees
;
QUIT;
%mend codegen ;

因此,如果我使用值 201605 调用该宏,它将生成此 SQL 查询。

CREATE TABLE WANT_201605 AS 
SELECT
  COUNT(A.canc_accts) AS canc_accts_0
 ,COUNT(x1.canc_accts) AS canc_accts_1 
 ,COUNT(x2.canc_accts) AS canc_accts_2 
 ,COUNT(x3.canc_accts) AS canc_accts_3 
 ,COUNT(x4.canc_accts) AS canc_accts_4 
 ,COUNT(x5.canc_accts) AS canc_accts_5 
 ,COUNT(x6.canc_accts) AS canc_accts_6 
 ,COUNT(x7.canc_accts) AS canc_accts_7 
 ,COUNT(x8.canc_accts) AS canc_accts_8 
 ,COUNT(x9.canc_accts) AS canc_accts_9 
 ,COUNT(x10.canc_accts) AS canc_accts_10 
 ,COUNT(x11.canc_accts) AS canc_accts_11 
 ,COUNT(x12.canc_accts) AS canc_accts_12 
FROM HAVE_DATA_201605 A
 LEFT JOIN HAVE_DATA_201606 x1 ON (A.ACCT_NO= x1.ACCT_NO) 
 LEFT JOIN HAVE_DATA_201607 x2 ON (A.ACCT_NO= x2.ACCT_NO) 
 LEFT JOIN HAVE_DATA_201608 x3 ON (A.ACCT_NO= x3.ACCT_NO) 
 LEFT JOIN HAVE_DATA_201609 x4 ON (A.ACCT_NO= x4.ACCT_NO) 
 LEFT JOIN HAVE_DATA_201610 x5 ON (A.ACCT_NO= x5.ACCT_NO) 
 LEFT JOIN HAVE_DATA_201611 x6 ON (A.ACCT_NO= x6.ACCT_NO) 
 LEFT JOIN HAVE_DATA_201612 x7 ON (A.ACCT_NO= x7.ACCT_NO) 
 LEFT JOIN HAVE_DATA_201701 x8 ON (A.ACCT_NO= x8.ACCT_NO) 
 LEFT JOIN HAVE_DATA_201702 x9 ON (A.ACCT_NO= x9.ACCT_NO) 
 LEFT JOIN HAVE_DATA_201703 x10 ON (A.ACCT_NO= x10.ACCT_NO) 
 LEFT JOIN HAVE_DATA_201704 x11 ON (A.ACCT_NO= x11.ACCT_NO) 
 LEFT JOIN HAVE_DATA_201705 x12 ON (A.ACCT_NO= x12.ACCT_NO) 
GROUP BY A.Fees 
;

【讨论】:

  • 非常感谢汤姆。这真的很有帮助。根据您的代码,我还有另一个主要问题。如果我需要多个表,我是否运行另一个宏?...就像上面的示例中的表是针对 201605 的,但是我需要在接下来的几个月(201606、201607 等)运行。
  • 要运行宏,您可以通过名称调用它并为其参数提供值。有很多方法可以生成对宏的多次调用。您可以自己重复通话。 %codegen(201605); %codegen(201606); 或者创建另一个宏来生成对该宏的多次调用。或者使用call execute() 从数据步骤生成调用。或者您可以更改宏以添加另一个循环,以便它可以创建多个数据集。
【解决方案2】:

使用宏来堆叠所有数据。堆栈器将添加一个新的分类变量“源”。然后在堆栈上进行计数/轴转换。

data have_201701;
   account = 1;
   fee = 'revert';
run;

%macro stack (out=, base=, from=, months=12);
    %local i ym ymf;

    %let ym = %sysfunc(inputn(&from,yymmn6));

    data &out / view=&out;
      set
         %do i = 1 %to &months; 

           %let ymf = %sysfunc(putn(&ym,yymmn6));
           &base.&ymf

           %let ym = %sysfunc(intnx(month,&ym,1));

         %end;             
         indsname = _source_
      ;
      source = _source_;
    run;
%mend;

options nodsnferr; * do not cause an error if the there is a request for a data set that is not found;

options mprint; * logging purposes only;
%stack (out=tall, base=have_, from=201612);
options nomprint;

* Now deal with one or two data transformation steps based on "tall" and new categorical variable "source" ;

您可以使用 SQL + TRANSPOSE、TABULATE、REPORT、HASH 或 ARRAY 进行透视。

最初的问题不够清楚,无法说明计数要求,尤其是在显示按帐户加入和按费用分组且未在所需输出中维护这些功能时。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-06
    • 1970-01-01
    • 1970-01-01
    • 2019-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多