我编写了一段代码,将创建多个包含 ID 的宏变量。然而,宏变量只能包含 65534 个字符。我的每个宏变量 ACC_i 都包含 65k 个变量。我想创建包含宏变量 ACC_1 - ACC_i 的宏变量,因此在代码中使用时将调用所有宏。
这是我到目前为止的代码,请提供帮助
%MACRO LOOP();
proc sql; select Count(*) as CNT ,MAX(LENGTH(Column1)) FORMAT 2.0 as LEN into: CNT, :LEN from table
; quit;
%put &CNT. &LEN.;
%let RUNS = %sysfunc(CEIL(&CNT./(65534/&LEN.)));
%LET OBS = %sysfunc(FLOOR(((65534/&LEN.))));
data TEST;
set &table.;
run;
%put &RUNS.;
%put &OBS.;
%let ACC = .;
%global i;
%DO i = 1 %to &RUNS.;
%global ACC_&i.;
proc sql inobs=&OBS.;
select input(&ID.,16.) FORMAT 16. as ACC_&i. into: ACC_&i. SEPARATED BY " ,"
from TEST
;quit;
data TEST;
set TEST nobs=count;
if _n_ <= &OBS. then delete;
run;
%END;
%mend;
%LOOP();
根据您想要做什么,可能有一种通过使用表格来实现此目的的更佳方法。但是,这是一个有趣的编程挑战,所以这里有一个可以满足您需求的解决方案。
最简单的方法是创建一个表,将您的 ID 分成几组。我们将累计计算所有值的长度,加上 2 以考虑空格和逗号,并在超过 65534 时增加组计数器。
请注意,如果您的 ID 是数字,请先使用
strip(put(num_var, 32.))
将其转换为字符,否则 SAS 将不会给出预期的答案。
/* Sample data */
data have;
do i = 1 to 100000;
id = put(rand('integer', 100000), z8.);
output;
end;
drop i;
run;
data id_groups;
set have;
retain group;
if(_N_ = 1) then group = 1;
/* Add +2 to account for ', ' */
cumulative_len+(length(id)+2);
if(cumulative_len > 65534) then do;
group+1;
cumulative_len = length(id)+2;
end;
call symputx('ngroups', group);
keep id group;
run;
id group cumulative_len
00058330 1 10
00099363 1 20
00058789 1 30
... ... ...
00051947 1 65520
00066223 1 65530
00064104 2 10
00060774 2 20
...
我们知道组的总数,因此我们将循环它们并为每个组创建一个宏变量。然后我们将所有这些保存到一个名为
all_macvars
的宏变量中。
%macro create_vars;
%global all_macvars;
%do i = 1 %to &ngroups;
%global id_&i.;
proc sql noprint;
select id
into :id_&i. separated by ', '
from id_groups
where group=&i
;
quit;
%let all_macvars = &all_macvars %nrstr(&id_)&i.;
%end;
%mend;
%create_vars;
%put &all_macvars
%put &id_1
&id_1 &id_2 &id_3 &id_4 &id_5 &id_6
&id_7 &id_8 &id_9 &id_10 &id_11 &id_12
...
00058330, 00099363, 00058789, 00085747, 00082469,
00028057, 00064740, 00038192, 00044896, 00087579,
00051839, 00084268, 00027839, 00093355, 00018740,
...