更新
鉴于这种使用INTNX
的新方法,我想我可以使用循环来简化事情。如果我制作了一个数组怎么办?
data;
array period [4] $ var1-var4 ('day' 'week' 'month' 'year');
run;
然后尝试为每个元素创建一个循环:
%MACRO sqlloop;
proc sql;
%DO k = 1 %TO dim(period); /* in case i decide to drop something from array later */
%LET bucket = &period(k)
CREATE TABLE output.t_&bucket AS (
SELECT INTX( "&bucket.", date_field, O, 'E') AS test FROM table);
%END
quit;
%MEND
%sqlloop
这不太有用,但它捕获了我想要的想法。它可以只为INTX中的每个值运行查询。这有意义吗?
我有几个先前的问题,我正在合并为一个。我对其他人提出了一些非常有用的建议,希望这可以将它们联系在一起。
我有以下函数创建一个动态字符串来填充SAS SELECT
代码块中的proc sql;
语句:
proc fcmp outlib = output.funcs.test;
function sqlSelectByDateRange(interval $, date_field $) $;
day = date_field||" AS day, ";
week = "WEEK("||date_field||") AS week, ";
month = "MONTH("||date_field||") AS month, ";
year = "YEAR("||date_field||") AS year, ";
IF interval = "week" THEN
do;
day = '';
end;
IF interval = "month" THEN
do;
day = '';
week = '';
end;
IF interval = "year" THEN
do;
day = '';
week = '';
month = '';
end;
where_string = day||week||month||year;
return(where_string);
endsub;
quit;
我已经确认这会创建我想要的字符串:
data _null_;
q = sqlSelectByDateRange('month', 'myDateColumn');
put q =;
run;
这会产生:
q=MONTH(myDateColumn) AS month, YEAR(myDateColumn) AS year,
这正是我想要的SQL字符串。从以前的问题来看,我认为我需要在MACRO
中调用此函数。然后我想要这样的事情:
%MACRO sqlSelectByDateRange(interval, date_field);
/* Code I can't figure out */
%MEND
PROC SQL;
CREATE TABLE output.t AS (
SELECT
%sqlSelectByDateRange('month', 'myDateColumn')
FROM
output.myTable
);
QUIT;
我无法理解如何使代码调用此宏并将其解释为SQL SELECT字符串的一部分。我在其他答案中尝试了一些前面的例子,但我无法使其工作。我希望这个更具体的问题可以帮助我填补这个缺失的步骤,以便我将来可以学习如何做到这一点。
答案 0 :(得分:3)
两件事:
首先,您应该可以使用%SYSFUNC来调用自定义函数。
%MACRO sqlSelectByDateRange(interval, date_field);
%SYSFUNC( sqlSelectByDateRange(&interval., &date_field.) )
%MEND;
请注意,在通过SYSFUNC调用函数时不应使用引号。另外,you cannot use SYSFUNC with FCMP functions until SAS 9.2。如果您使用的是早期版本,则无法使用。
其次,您的select子句中有一个尾随逗号。您可能需要一个虚拟列,如下所示:
PROC SQL;
CREATE TABLE output.t AS (
SELECT
%sqlSelectByDateRange('month', 'myDateColumn')
0 AS dummy
FROM
output.myTable
);
QUIT;
(请注意dummy
之前没有逗号,因为逗号已经嵌入到您的宏中。)
<强>更新强>
我在另一个答案中读到你的评论:
我还需要能够针对不同的日期范围和非常特别的方式来做这件事,所以我想说“从6月到12月的月份”或“每周两周”等等。有人提出要求。
我想我可以推荐一种更简单的方法来达到你正在做的事情。首先,我将创建一个包含日期和值的非常简单的数据集。日期分布在不同的日期,周,月和年:
DATA Work.Accounts;
Format Opened yymmdd10.
Value dollar14.2
;
INPUT Opened yymmdd10.
Value dollar14.2
;
DATALINES;
2012-12-31 $90,000.00
2013-01-01 $100,000.00
2013-01-02 $200,000.00
2013-01-03 $150,000.00
2013-01-15 $250,000.00
2013-02-10 $120,000.00
2013-02-14 $230,000.00
2013-03-01 $900,000.00
RUN;
您现在可以使用INTNX
功能创建第三列,将“已打开”列舍入到某个时间段,例如'WEEK'
,'MONTH'
或{{1 (见complete list):
'YEAR'
%LET Period = YEAR;
PROC SQL NOPRINT;
CREATE TABLE Work.PeriodSummary AS
SELECT INTNX( "&Period.", Opened, 0, 'E' ) AS Period_End FORMAT=yymmdd10.
, SUM( Value ) AS TotalValue FORMAT=dollar14.
FROM Work.Accounts
GROUP BY Period_End
;
QUIT;
的输出:
WEEK
Period_End TotalValue
2013-01-05 $540,000
2013-01-19 $250,000
2013-02-16 $350,000
2013-03-02 $900,000
的输出:
MONTH
Period_End TotalValue
2012-12-31 $90,000
2013-01-31 $700,000
2013-02-28 $350,000
2013-03-31 $900,000
的输出:
YEAR
答案 1 :(得分:2)
正如Cyborg37所说,你可能应该在你的函数中摆脱那个尾随的逗号。但请注意,您不需要创建宏来执行此操作,只需直接使用%SYSFUNC
函数:
proc sql;
create table output.t as
select %sysfunc( sqlSelectByDateRange(month, myDateColumn) )
* /* to avoid the trailing comma */
from output.myTable;
quit;
此外,虽然这是对用户定义函数的巧妙使用,但是为什么要这样做还不是很清楚。可能有更好的解决方案,不会在代码中造成太多可能的混淆。用户定义的函数(如用户编写的宏)可以使生活更轻松,但它们也可以创建管理噩梦。
答案 2 :(得分:1)
我可以对你为什么会犯错误做出各种猜测,但从根本上说,不要这样做。您可以完成您在数据步骤中尝试执行的操作,该操作比FCMP功能更容易进行故障排除并且更容易实现,而FCMP功能实际上只是尝试成为数据步骤。
步骤: 1.创建一个具有可能日期提取的数据集。如果你经常使用它,可以将它放在SAS AUTOEXEC中定义的永久库中。 2.创建一个从中提取所需日期字符串的宏。 3.如果需要,使用PROC FCMP使用RUN_MACRO将其设置为函数式宏。 4.如果这样做,请使用%SYSFUNC来调用它。
这是做到这一点的事情:
1:
data pull_list;
infile datalines dlm='|';
length query $50. type $8.;
input type $ typenum query $;
datalines;
day|1|&date_field. as day
week|2|week(&date_field.) as week
month|3|month(&date_field.) as month
year|4|year(&date_field.) as year
;;;;
run;
2:
%macro pull_list(type=,date_field=);
%let date_field = datevar;
%let type = week;
proc sql noprint;
select query into :sellist separated by ','
from pull_list
where typenum >= (select typenum from pull_list where type="&type.");
quit;
%mend pull_list;
3:
proc fcmp outlib = work.functions.funcs;
function pull_list(type $,date_field $) $;
rc = run_macro('pull_list', type,date_field);
if rc eq 0 then return("&sellist.");
else return(' ');
endsub;
run;
4:
data test;
input datevar 5.;
datalines;
18963
19632
18131
19105
;;;;
run;
option cmplib = (work.functions);
proc sql;
select %sysfunc(pull_list(week,datevar)) from test;
quit;
这样做的一大优点是您可以添加其他类型而无需担心函数的代码 - 只需在pull_list中添加一行即可。如果你想设置它,我建议使用1,2,3,4以外的东西来使用typenum - 使用10,20,30,40或者其他东西,这样你就有空隙(比方说,如果&#34; twoweek& #34;被添加,它将介于2和3之间,25比人们更容易思考25。创建pull_list数据集,将其放在网络驱动器上,您的所有用户都可以使用它(如果您之外的任何人使用它,或者如果没有,则使用个人),然后从那里开始。