从Teradata到PROC SQL的SQL语句语法
我是SAS的新手,我正在尝试使用proc sql构建一些查询 我有以下sql代码(teradata语法): 我希望得到以下输出: 对于日期为1的每个客户id和YYYYMM,合计过去6个月的Flag1和sum Flag1累计值 用同样的语法,我会做:从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
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[索引];对吗?还有一个问题,很抱歉,我忘了问这个问题:如果我想计算每个客户的标志总数,该怎么办