SAS技术问询:在函数/子程序中查找数据并返回数组
解决FCMP函数读取数据集并返回匹配值的问题
首先得明确:PROC FCMP函数里不能直接用SET语句读取数据集,这是你之前尝试失败的核心原因。不过我们可以借助SAS哈希对象来绕开这个限制——哈希对象可以在FCMP函数内部初始化并加载数据集,而且用STATIC关键字能让它只加载一次,避免重复读取数据影响效率。
下面是完整的实现代码,分两种常用场景:返回拼接字符串(适合在PROC SQL/DATA步直接调用),以及返回数组(适合需要单独处理每个值的场景)。
场景1:返回逗号分隔的MyVar2字符串
这个版本最通用,能直接在PROC SQL或DATA步里作为函数调用,返回所有匹配的MyVar2值,用逗号分隔:
/* 1. 创建测试用的MyData数据集(替换成你自己的数据集即可) */ data MyData; input MyVar1 $ MyVar2 $; datalines; A Apple A Apricot B Banana B Blueberry C Cherry ; run; /* 2. 用PROC FCMP编写函数 */ proc fcmp outlib=work.funcs.MyFunction; function GetMyVar2(InParameter $) $; /* 定义静态哈希对象,确保只初始化一次 */ declare hash h(ordered:'a'); declare hiter iter('h'); length MyVar1 $ 10 MyVar2 $ 20 key $ 10 value $ 20; static init_flag; /* 第一次调用时加载数据集到哈希表 */ if init_flag ne 1 then do; h.definekey('MyVar1'); h.definedata('MyVar2'); h.definedone(); h.load(dataset:'MyData'); /* 加载你的目标数据集 */ init_flag = 1; end; /* 查找所有匹配InParameter的MyVar2值,拼接成字符串 */ length result $ 200; result = ''; key = InParameter; do while(iter.next()=0); if MyVar1 = key then do; if result ne '' then result = catx(', ', result, MyVar2); else result = MyVar2; end; end; return(result); endfunc; run; /* 3. 设置SAS系统选项,让函数能被全局调用 */ options cmplib=work.funcs; /* 4. 测试:在DATA步调用 */ data test_data_step; input InputParam $; MyVar2_List = GetMyVar2(InputParam); datalines; A B C D ; run; /* 5. 测试:在PROC SQL调用 */ proc sql; select distinct MyVar1, GetMyVar2(MyVar1) as MyVar2_List from MyData; quit;
场景2:返回MyVar2数组(用子程序实现)
如果你需要单独处理每个匹配的MyVar2值,可以用FCMP子程序(SUBROUTINE)来返回数组:
proc fcmp outlib=work.funcs.MyFunction; subroutine GetMyVar2Array(InParameter $, out_array[*] $, out_count); outargs out_array, out_count; declare hash h(ordered:'a'); declare hiter iter('h'); length MyVar1 $ 10 MyVar2 $ 20 key $ 10; static init_flag; array temp[100] $ 20; /* 定义足够大的临时数组 */ out_count = 0; if init_flag ne 1 then do; h.definekey('MyVar1'); h.definedata('MyVar2'); h.definedone(); h.load(dataset:'MyData'); init_flag = 1; end; /* 收集所有匹配的值到临时数组 */ key = InParameter; do while(iter.next()=0); if MyVar1 = key then do; out_count + 1; temp[out_count] = MyVar2; end; end; /* 把临时数组的值赋值给输出数组 */ do i=1 to out_count; out_array[i] = temp[i]; end; endsub; run; /* 测试子程序 */ data test_subroutine; array results[5] $ 20; call GetMyVar2Array('A', results[*], count); put "匹配到的数量: " count; do i=1 to count; put "第" i "个值: " results[i]; end; run;
关键注意事项
- 用
STATIC关键字标记init_flag和哈希对象,确保数据集只被加载一次,大幅提升效率。 - 哈希对象的
ordered:'a'参数能让返回的结果按顺序排列,如果你不需要排序可以去掉。 - 如果你的
MyVar2是数值型,只需要修改对应的length语句和数组定义即可,比如把$去掉,调整长度为数值类型(比如length MyVar2 8;)。 - 记得设置
options cmplib=work.funcs;,否则SAS找不到你定义的函数/子程序。
内容的提问来源于stack exchange,提问作者Martin Dreher
相关产品推荐
相关产品推荐

