SAS/SQL-使用自定义函数创建SELECT语句
更新 考虑到这种使用SAS/SQL-使用自定义函数创建SELECT语句,sql,sas,Sql,Sas,更新 考虑到这种使用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
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
procsql中的SELECT
语句代码>代码块:
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 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选择字符串的一部分。我已经在其他答案中尝试了前面的一些例子,但我就是不能让它起作用。我希望这个更具体的问题能帮助我填补这一缺失的步骤,以便我将来能学会如何做。两件事:
首先,您应该能够使用调用自定义函数
%MACRO sqlSelectByDateRange(interval, date_field);
%SYSFUNC( sqlSelectByDateRange(&interval., &date_field.) )
%MEND;
请注意,通过SYSFUNC调用函数时不应使用引号。也。如果您使用的是早期版本,这将不起作用
其次,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
函数创建第三列,将“已打开”列四舍五入到某个时间段,例如“周”
,“月”
,或“年”
(请参见此):
周的输出
:
Period\u End TotalValue
2013-01-05 $540,000
2013-01-19 $250,000
2013-02-16 $350,000
2013-03-02 $900,000
月份的输出
:
Period\u End TotalValue
2012-12-31 $90,000
2013-01-31 $700,000
2013-02-28 $350,000
2013-03-31 $900,000
年度的输出
:
Period\u End TotalValue
2012-12-31 $90,000
2013-12-31 $1,950,000
正如Cyborg37所说,您可能应该在函数中去掉后面的逗号。但请注意,执行此操作实际上不需要创建宏,只需直接使用%SYSFUNC
函数即可:
proc sql;
create table output.t as
select %sysfunc( sqlSelectByDateRange(month, myDateColumn) )
* /* to avoid the trailing comma */
from output.myTable;
quit;
此外,尽管这是用户定义函数的巧妙使用,但您为什么要这样做还不是很清楚。可能有更好的解决方案,不会在代码中造成太多潜在的混乱。用户定义的函数,如用户编写的宏,可以让生活变得更轻松,但它们也会造成管理噩梦。我可以对出现错误的原因进行各种猜测,但基本上,不要这样做。与FCMP函数相比,数据步骤更容易排除故障,也更容易实现。FCMP函数实际上只是一个数据步骤
步骤:
1.创建一个包含可能日期的数据集。如果您经常使用它,可以将其放入SAS AUTOEXEC中定义的永久库中。
2.创建一个宏,从中提取所需的日期字符串。
3.如果需要,可以使用PROC FCMP,使用RUN_宏使其成为函数样式的宏。
4.如果这样做,请使用%SYSFUNC调用它
这里有一些东西可以做到这一点:
1:
2:
3:
4:
这样做的一大优点是,您可以添加其他类型,而不必担心函数的代码——只需添加一行到pull_list,它就可以工作了。如果你想把它设置成这样,我建议对typenum使用1,2,3,4以外的东西-使用10,20,30,40或其他一些你有空白的东西(比如,如果加上“twoweek”,它将在2到3之间,25比2.5更容易让人思考)。创建pull_列表数据集,将其放在网络驱动器上,您的所有用户都可以使用它(如果您以外的人使用它,或者如果没有人使用它),然后从那里开始。是的,这很有意义。不过,我在长度方面也遇到了同样的错误。我不知道那是怎么回事。至于为什么,我很想听听你的想法。我将运行一些需要按时间范围(天、周、月、年等)分组的报告。理想情况下,我更愿意按天运行数据集,并按照我的意愿对其进行聚合。不幸的是,我查询的一个主要领域是不同的个人,他们可能会在数周或数月内有所不同。考虑到数据的大小,在导出摘要之前,我希望在给定的级别上执行不同的计数。我还需要能够针对不同的日期范围和非常特殊的基础进行计数,因此我想说的是“从6月到12月按月”或“两年内每周”当有人提出请求时,@JeffreyKramer-我可能有一个更简单的方法让你实现你的目标。看看上面,你没有在你的函数中定义事物的长度,所以你冒着事情变得非常大的风险——也许所有这些都发生了
proc sql;
create table output.t as
select %sysfunc( sqlSelectByDateRange(month, myDateColumn) )
* /* to avoid the trailing comma */
from output.myTable;
quit;
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;
%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;
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;
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;