从Teradata到PROC SQL的SQL语句语法

从Teradata到PROC SQL的SQL语句语法,sql,sas,teradata,proc-sql,Sql,Sas,Teradata,Proc Sql,我是SAS的新手,我正在尝试使用proc sql构建一些查询 我有以下sql代码(teradata语法): 我希望得到以下输出: 对于日期为1的每个客户id和YYYYMM,合计过去6个月的Flag1和sum Flag1累计值 用同样的语法,我会做: with cte_data_ts (ts1, Flag1) as ( select cast(date1 as timestamp(0)), Flag1 from mvt_data ) , cte_gbt (YearMonth, SumFl

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

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

我希望得到以下输出:

对于日期为1的每个客户id和YYYYMM,合计过去6个月的Flag1和sum Flag1累计值

用同样的语法,我会做:

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数据步骤,以便处理一些数据

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的最小/最大值,并使用这些值设置日期范围

如果客户id值列表没有其他来源,则可以查询数据

select distinct cust_id from mvt_data
因此,加入这两个,获得完整的YearMonth*客户id组合

select x.cust_id,y.YearMonth 
   from (select distinct cust_id from mvt_data) x
      , YearMonth y
现在将其与实际数据合并,以获得每月设置FLAG1的计数。您可以使用SAS将布尔表达式求值为0/1的事实来简化代码。(在通用SQL实现中,您需要使用用例)因此,当标记观察的日期在时间间隔内时,它为SUM()贡献1

结果:

                    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
 ...
         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

因此,首先让我们将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的最小/最大值,并使用这些值设置日期范围

如果客户id值列表没有其他来源,则可以查询数据

select distinct cust_id from mvt_data
因此,加入这两个,获得完整的YearMonth*客户id组合

select x.cust_id,y.YearMonth 
   from (select distinct cust_id from mvt_data) x
      , YearMonth y
现在将其与实际数据合并,以获得每月设置FLAG1的计数。您可以使用SAS将布尔表达式求值为0/1的事实来简化代码。(在通用SQL实现中,您需要使用用例)因此,当标记观察的日期在时间间隔内时,它为SUM()贡献1

结果:

                    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
 ...
         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

只使用数据步骤进行求和可能更快

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

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

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;

只使用数据步骤进行求和可能更快

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

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

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;

非常感谢。如果我还想计算12个月的sumFlag1_,我应该添加另一个左连接?或者您看到了在其他时间段中不继续添加左连接来计算的方法吗?让我更新以将日期测试移动到聚合函数调用中。这实际上可以消除额外的连接。谢谢你,汤姆!请查看编辑并在解决方案中添加客户id,好吗?那太完美了!对不起,我忘了那个字段:(要添加cust_id,您可能只想获得一个要加入查询的cust_id的独特列表,并将其包含在加入条件和分组依据中。非常感谢!!!谢谢!!如果我还想计算12个月的sumglag1,我应该添加另一个左连接?或者您是否看到这样做而不继续添加左连接来计算其他内容er时间段?让我更新以将日期测试移动到聚合函数调用中。这实际上可以消除额外的连接。谢谢你,Tom!你能看到编辑并在解决方案中添加客户id吗?这太完美了!抱歉,我忘记了该字段:(若要添加客户id,您可能只想获得一个客户id的独特列表以加入查询,并将其包括在加入条件和分组依据中。非常感谢!!!谢谢!!如果我要计算最近12个月的sumFlag1,则还必须添加sumFlag1\u最近12个月=sumFlag1;do index=max(0,偏移量-12)为了抵消-1;SumFlag1_last12Months=SumFlag1_last12Months+month[index];是否正确?还有一个问题,很抱歉,我忘了问这个问题:如果我想计算每个客户的标志总和,该怎么办?因此添加一列“customer_id”?按组添加CUSTOMER\u ID很简单。在设置之后添加BY语句。添加IF FIRST.CUSTOMER\u ID测试何时将accumlator数组重置为零。将IF EOF更改为IF LAST.CUSTOMER\u ID。不要忘记保留BY变量。谢谢!!如果我想计算sumFlag1_last12Months还必须将sumFlag1_last12Months=sumFlag1;do index=max(0,offset-12)添加到offset-1;sumFlag1_last12Months=sumFlag1_last12Months+month[索引];对吗?还有一个问题,很抱歉,我忘了问这个问题:如果我想计算每个客户的标志总数,该怎么办