您写道,我不应该在%macro中设置%macro。所以请帮忙 创世记:我有一张表,其中存储着每天开始的所有SAS流程-但各种报告应在每天运行-根据“ Nr_week_day”字段。如果今天包含在此字段中-我将此过程放到general_stock表中运行。 以下是带注释的代码-我想要得到的代码。 通常,此代码有效,但可以在宏中使用宏。也许您有更好的主意,什么可以工作。 这个过程与我的另一个“问题”有关: SAS include dynamic path SAS Macro in macro
data CONTROL_FILES_BASE;
input Priority : 2.
ACTIVE: 1.
PROCES_NAME: $10.
Nr_week_day: $10.
; cards;
1 1 TEST_01 (1,3,6)
2 1 TEST_02 0
3 1 TEST_03 (4,5)
;
Data Kalendariusz;
infile cards dlm=',' dsd;
input ref_date: date9.
Nr_day_of_month
Nr_week_day
Number_date;
Format ref_date DDMMYY10.;
cards;
01NOV2018, 1, 4, 20181101
02NOV2018, 2, 5, 20181102
03NOV2018, 3, 6, 20181103
04NOV2018, 4, 7, 20181104
05NOV2018, 5, 1, 20181105
06NOV2018, 6, 2, 20181106
07NOV2018, 7, 3, 20181107
08NOV2018, 8, 4, 20181108
09NOV2018, 9, 5, 20181109
10NOV2018, 10, 6, 20181110
11NOV2018, 11, 7, 20181111
12NOV2018, 12, 1, 20181112
13NOV2018, 13, 2, 20181113
14NOV2018, 14, 3, 20181114
15NOV2018, 15, 4, 20181115
16NOV2018, 16, 5, 20181116
17NOV2018, 17, 6, 20181117
18NOV2018, 18, 7, 20181118
19NOV2018, 19, 1, 20181119
20NOV2018, 20, 2, 20181120
21NOV2018, 21, 3, 20181121
22NOV2018, 22, 4, 20181122
23NOV2018, 23, 5, 20181123
24NOV2018, 24, 6, 20181124
25NOV2018, 25, 7, 20181125
26NOV2018, 26, 1, 20181126
27NOV2018, 27, 2, 20181127
28NOV2018, 28, 3, 20181128
29NOV2018, 29, 4, 20181129
30NOV2018, 30, 5, 20181130
;
/*COMMENT: I TAKE TODAY IN VARIABLE*/
%LET EXTRACT_DATE_DT = date();
/*COMMENT: I CREATE EMPTY TABLE TO STOCK OF PROCESS*/
Proc sql;
Create table GENERAL_STOCK as
Select
*
FROM WORK.CONTROL_FILES_BASE
WHERE ACTIVE = 2
;quit;
/*START MAIN MACRO*/
%macro GENERATE_STOCK();
/*COMMENT: I check how many processes should be generated.*/
PROC SQL noprint;
Select
count(*) into :i
From work.CONTROL_FILES_BASE
WHERE Nr_week_day <> '0'
;quit;
%PUT &i;
/*COMMENT: I separated process which should be check*/
Proc sql;
Create table STOCK_2 as
Select
monotonic() as ROW_ID,
*
FROM work.CONTROL_FILES_BASE
WHERE Nr_week_day ne '0'
;quit;
/*MAIN LOOP - I take field NR_WEEK_DAY and will check that this number of day is today - row by row*/
%do ITER = 1 %To &i;
Proc sql;
Select
Nr_week_day into :SET_VAR
from STOCK_2
WHERE ROW_ID = &ITER
;quit;
%PUT &SET_VAR;
/*SET_VAR have value from Nr_week_day*/
%LET l_decision = 0;/*I set default value in variable*/
/*below code I found in forum - this macro reverse query - check whether (1,3,6) is included today - in table KALENDARIUSZ*/
%macro nos_obs(dsn=,where_stmt=);
proc sql;
select
count(*)
into :l_decision
from &dsn.
&where_stmt.
;quit;
%mend ;
%nos_obs(dsn=Kalendariusz,where_stmt=where Nr_week_day in &&SET_VAR. and Ref_date = &EXTRACT_DATE_DT.);
%PUT &l_decision;
/*IF ABOVE CODE RETURN 1 - means that the nr_week_day is today */
/*When l_decisions is 1 then process should add this row to general_stock. If 0 - should add nothing.*/
%if &l_decision = 1 %then
%do;
Proc sql;
Create table STOCK_2_INSERT (drop=ROW_ID) as
Select
*
FROM WORK.STOCK_2
WHERE ROW_ID = &ITER
;quit;
Proc sql;
insert into GENERAL_STOCK
select * from work.STOCK_2_INSERT
;quit;
/*I clear temp table*/
Proc sql;
delete FROM WORK.STOCK_2_INSERT
;quit;
%end;
%else %if &l_decision = 0 %then
%do;
%end;
%end;
%mend GENERATE_STOCK;
%GENERATE_STOCK();
/*AND I LOOK AT GENERAL TABLE*/
Proc sql;
Create table SHOW_GENERAL_STOCK as
Select
*
FROM WORK.GENERAL_STOCK
;quit;
答案 0 :(得分:2)
如您的other question的答案中所述,在另一个宏定义中定义一个宏是一个坏主意。在您的示例中,这意味着您可以移动实用程序宏%nos_obs的定义:
%macro nos_obs(dsn=,where_stmt=);
proc sql;
select
count(*)
into :l_decision
from &dsn.
&where_stmt.
;quit;
%mend ;
该代码块不应位于该代码块之内:
%macro GENERATE_STOCK;
...
%mend GENERATE_STOCK;
您仍然可以从%generate_stock内部调用%nos_obs。只是不要嵌套宏定义。因此,您最终得到:
*define a macro;
%macro nos_obs(dsn=,where_stmt=);
...
%mend ;
*define a macro that does some stuff and invokes another macro;
%macro GENERATE_STOCK;
...
%nos_obs(dsn=...)
...
%mend GENERATE_STOCK;
%generatestock
这是不嵌套宏定义的要点。大致来说,您似乎在用SAS编写调度程序。像linux cron或Windows Scheduler一样,您可以根据星期几决定要运行的程序。 通常,最好使用专用的调度程序解决方案(cron,LSF,Windows调度程序等),而不是编写自己的解决方案。更好的意味着更轻松,更可维护,更灵活等。它们将使您能够进行管理依赖项,暂停和重新启动等)。
也就是说,如果您确实使用SAS编写了自己的调度程序(很多人这样做,有时很难抗拒这种诱惑),那么我认为您所显示的代码要复杂得多。
您有一个控制数据集,其中列出了每个进程应运行的日期:
data CONTROL_FILES_BASE;
input Priority : 2.
ACTIVE: 1.
PROCES_NAME: $10.
Nr_week_day: $10.
; cards;
1 1 TEST_01 (1,3,6)
2 1 TEST_02 0
3 1 TEST_03 (4,5)
;
如果要确定今天应该运行哪些进程,则只需找出今天是星期几,然后相应地选择记录即可。像这样:
data General_Stock ;
set CONTROL_FILES_BASE ;
where findc(Nr_week_day,put(weekday(today()),1.)) ;
run ;
当我写这篇文章的时候是星期六,所以工作日(today())返回7,并且上面没有选择0条记录,因为没有计划在星期六运行。
如果要使用宏,因为要进行测试以查看控件数据集将在不同日期触发的进程,因此可以在输入提取日期的地方编写一个小宏。像这样:
%macro GENERATE_STOCK
(data=/*name of input control dataset*/
,out= /*name of output dataset*/
,ExtractDate=/*extract date is a SAS date or expression like today() */
);
data &out ;
set &data ;
where findc(Nr_week_day,put(weekday(&extractDate),1.)) ;
run ;
title1 "Printout of &out genenerated when ExtractDate=%superq(ExtractDate)" ;
proc print data=&out ;
run ;
title1 ;
%mend GENERATE_STOCK ;
测试方式:
%generate_stock(data=control_files_base,out=wantToday ,extractdate=today())
%generate_stock(data=control_files_base,out=wantSunday ,extractdate="11Nov2018"d)
%generate_stock(data=control_files_base,out=wantMonday ,extractdate="12Nov2018"d)
%generate_stock(data=control_files_base,out=wantTuesday ,extractdate="13Nov2018"d)
%generate_stock(data=control_files_base,out=wantWednesday,extractdate="14Nov2018"d)
%generate_stock(data=control_files_base,out=wantThursday ,extractdate="15Nov2018"d)
%generate_stock(data=control_files_base,out=wantFriday ,extractdate="16Nov2018"d)
%generate_stock(data=control_files_base,out=wantSaturday ,extractdate="17Nov2018"d)