【问题标题】:SQL statment syntax from Teradata to PROC SQL从 Teradata 到 PROC SQL 的 SQL 语句语法
【发布时间】:2021-07-28 22:30:47
【问题描述】:

我是 SAS 新手,我正在尝试使用 proc sql 构建一些查询。

我在 sql 中有以下代码(teradata 语法):

create multiset volatile table mvt_data, no log
( date1     date format 'yyyy-mm-dd'
, flag1     byteint
,cust_id    varchar(25)
)
primary index (date1)
on commit preserve rows;

insert into mvt_data values (date '2020-01-03', 1, 'A');
insert into mvt_data values (date '2020-02-04', 0, 'A');
insert into mvt_data values (date '2020-04-05', 0, 'B');
insert into mvt_data values (date '2020-01-19', 1, 'C');
insert into mvt_data values (date '2020-03-20', 1, 'B');
insert into mvt_data values (date '2020-06-20', 1, 'D');

我想要以下输出:

对于 date1 的每个 Cust_id 和 YYYYMM 求和 Flag1 和总和 Flag1 相对于过去 6 个月的累积。

我会使用相同的语法:

with cte_data_ts (ts1, Flag1) as
(
select cast(date1 as timestamp(0)), Flag1
  from mvt_data
)
  ,  cte_gbt (YearMonth, SumFlag1, cust_id) as
(
  select cust_id                                          as cust_id
       ,to_char(begin($TD_TIMECODE_RANGE) at 0, 'yyyymm') as YearMonth
       , sum(flag1)                                       as SumFlag1
    from cte_data_ts
group by time(cal_months(1))
   using timecode(ts1)
    fill (0)
)
  select cust_id, YearMonth, SumFlag1
       , sum(SumFlag1) over(order by cust_id, YearMonth asc rows between 6 preceding and current row) as SumFlag1_last6Months
    from cte_gbt;

不幸的是,我知道 proc sql 中不存在 over(),所以任何人都可以帮我实现相同的结果吗?

编辑:

我添加了一个新列 (Cust_ID)

【问题讨论】:

    标签: sql sas teradata proc-sql


    【解决方案1】:

    首先让我们将 SQL 数据加载转换为普通的 SAS 数据步骤,以便处理一些数据。

    data mvt_data;
      input date1 :yymmdd. flag1 cust_id $;
      format date1 yymmdd10.;
    cards;
    2020-01-03 1 A
    2020-02-04 0 A
    2020-04-05 0 B
    2020-01-19 1 C
    2020-03-20 1 B
    2020-06-20 1 D
    ;
    

    这是一种生成未出现在源中的月份的观察值的方法。

    data YearMonth;
      min='01JAN2020'd ;
      max='01JUN2020'd;
      do offset=0 to intck('month',min,max);
        do YearMonth=intnx('month',min,offset,'b') ;
          output;
        end;
      end;
      keep YearMonth ;
      format YearMonth yymmn6.;
    run;
    

    或者计算 DATE1 的最小/最大值并使用它们来设置日期范围。

    如果您没有其他来源的 Cust_id 值列表,您可以查询数据

    select distinct cust_id from mvt_data
    

    因此,将两者结合以获得完整的 YearMonth*Cust_id 组合。

    select x.cust_id,y.YearMonth 
       from (select distinct cust_id from mvt_data) x
          , YearMonth y
    

    现在将其与实际数据相结合,以获得每月设置 FLAG1 的计数。您可以使用 SAS 将布尔表达式计算为 0/1 值的事实来简化代码。 (在通用 SQL 实现中,您需要使用 CASE)因此,当标记观察的日期在区间内时,它将为 SUM() 贡献 1。

    proc sql ;
     create table want as
     select a.cust_id
          , a.YearMonth
          , sum(b.date1 between intnx('month',a.YearMonth,0,'b')
                            and intnx('month',a.YearMonth,0,'e') ) as SumFlag1
          , sum(b.date1 between intnx('month',a.YearMonth,-6,'b')
                            and intnx('month',a.YearMonth,0,'e') ) as SumFlag1_last6Months 
          , sum(b.date1 between intnx('month',a.YearMonth,-12,'b')
                            and intnx('month',a.YearMonth,0,'e') ) as SumFlag1_last12Months 
     from 
      (select x.cust_id,y.YearMonth 
       from (select distinct cust_id from mvt_data) x
          , YearMonth y
      ) a
     left join mvt_data b
       on a.cust_id = b.cust_id and b.Flag1=1
     group by 1,2
     ;
    quit;
    

    结果:

                        Year     Sum      SumFlag1_       SumFlag1_
    Obs    cust_id     Month    Flag1    last6Months    last12Months
    
      1       A       202001      1           1               1
      2       A       202002      0           1               1
      3       A       202003      0           1               1
      4       A       202004      0           1               1
      5       A       202005      0           1               1
      6       A       202006      0           1               1
      7       B       202001      0           0               0
      8       B       202002      0           0               0
      9       B       202003      1           1               1
     10       B       202004      0           1               1
     11       B       202005      0           1               1
     12       B       202006      0           1               1
     ...
    

    【讨论】:

    • 谢谢!!如果我还想计算 sumFlag1_last12Months,我应该添加另一个左连接吗?或者您是否看到在其他时间段不继续添加左连接来计算的情况下这样做?
    • 让我更新以在聚合函数调用中移动日期测试。这实际上可以消除额外的连接。
    • 谢谢汤姆!您能否查看编辑并在您的解决方案中添加 cust_id ?这将是完美的!抱歉,我忘记了那个字段:(
    • 要添加 cust_id,您可能只想获取一个不同的 cust_id 列表以加入查询并将其包含在加入条件和分组依据中。
    【解决方案2】:

    仅使用数据步骤进行汇总可能更快。

    例如,您可以使用一个每月一项的临时数组来进行累积。

    因此,首先找到您想要包含的第一个月中的一天以及之后的月数。您可以使用源数据中日期值的月份范围或设置一些固定范围。

    proc sql noprint;
      select min(date1)
           , intck('month',min(date1),max(date1))
        into :min_date trimmed
           , :nmonths trimmed
       from mvt_data
      ;
    quit;
    

    现在使用最小日期和月数来驱动计数数据步骤。

    读入所有记录(只需要设置 FLAG1 的记录)。使用 INTCK() 函数计算出数组的偏移量,并增加该月的累加器。在数组的最后循环并计算任何更大的月份间隔并每月输出一个观察结果。

    data want ;
      array month[0:&nmonths] _temporary_ (0 &nmonths*0) ;
      set mvt_data end=eof;
      where Flag1 ;
      offset = intck('month',&min_date,date1);
      if (0<= offset <= &nmonths) then month[offset]+1;
      if eof then do offset=0 to &nmonths;
        YearMonth = intnx('month',&min_date,offset);
        SumFlag1 = month[offset];
        SumFlag1_last6Months = SumFlag1;
        do index=max(0,offset-6) to offset-1;
           SumFlag1_last6Months = SumFlag1_last6Months+month[index];
        end;
        output;
      end;
      keep YearMonth SumFlag1 SumFlag1_last6Months;
      format YearMonth yymmn6. ;
    run;
    

    结果:

             Year     Sum      SumFlag1_
    Obs     Month    Flag1    last6Months
    
     1     202001      2           2
     2     202002      0           2
     3     202003      1           3
     4     202004      0           3
     5     202005      0           3
     6     202006      1           4
    

    【讨论】:

    • 谢谢!!如果我想计算 sumFlag1_last12Months 还必须添加 SumFlag1_last12Months = SumFlag1;执行 index=max(0,offset-12) 到 offset-1; SumFlag1_last12Months = SumFlag1_last12Months+month[index];对吗?
    • 还有一个问题,很抱歉,我忘了问这个问题:如果我想计算每个客户的标志总和怎么办?所以添加一列“customer_id”?
    • 为 CUSTOMER_ID 添加 BY 组处理很简单。在 SET 之后添加 BY 语句。添加 IF FIRST.CUSTOMER_ID 测试何时将累加器数组重置为零。将 IF EOF 更改为 IF LAST.CUSTOMER_ID。不要忘记保留 by 变量。
    猜你喜欢
    • 1970-01-01
    • 2015-09-30
    • 2013-08-18
    • 1970-01-01
    • 1970-01-01
    • 2019-02-05
    • 1970-01-01
    • 2022-11-23
    • 1970-01-01
    相关资源
    最近更新 更多