基于SAS宏的多表名与列名验证及错误处理技术问询
SAS宏验证表名/列名合规性及错误码返回实现方案
需求概述
- 实现带DO循环的SAS宏,验证表名(源表、目标表)和列名仅包含字母(大小写)和下划线
- 主程序调用宏时,触发错误需生成对应错误码并返回,主程序可基于错误码控制后续流程
现有代码问题分析
- 字符校验逻辑错误:原宏中用
%substr取单个字符后,直接与字符组(如"0-9")比较,SAS宏无法识别这种范围匹配,导致校验失效 - 校验范围不全:仅校验了
source_table,未覆盖target_table和目标列名trgt_col - 空值判断不准确:
&source_table.=""的写法在宏中可能因宏变量未初始化导致判断失效,应使用长度判断或宏函数判断空值 - 错误码缺失:仅输出错误信息,未生成可被主程序捕获的错误码
- 冗余代码:
%do循环内手动递增i是多余的,循环会自动处理索引;宏定义后直接调用%check_table,会导致主程序调用前提前执行校验
修正后的宏代码实现
%macro check_table(error_code=); /* 初始化错误码:0=无错误,1=表名/列名为空,2=包含非法字符 */ %let &error_code.=0; /* 定义合法字符集:大小写字母、下划线 */ %let valid_chars=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_; /* -------------------------- 校验源表名 -------------------------- */ %if %length(&source_table.)=0 %then %do; %put ERROR: 源表名不能为空; %let &error_code.=1; %return; %end; %let len=%length(&source_table.); %do i=1 %to &len.; %let char=%substr(&source_table.,&i,1); /* 检查字符是否在合法集合中 */ %if %verify(&char.,&valid_chars.)>0 %then %do; %put ERROR: 源表名包含非法字符:&char.,仅允许字母和下划线; %let &error_code.=2; %return; %end; %end; /* -------------------------- 校验目标表名 -------------------------- */ %if %length(&target_table.)=0 %then %do; %put ERROR: 目标表名不能为空; %let &error_code.=1; %return; %end; %let len=%length(&target_table.); %do i=1 %to &len.; %let char=%substr(&target_table.,&i,1); %if %verify(&char.,&valid_chars.)>0 %then %do; %put ERROR: 目标表名包含非法字符:&char.,仅允许字母和下划线; %let &error_code.=2; %return; %end; %end; /* -------------------------- 校验目标列名 -------------------------- */ %if %length(&trgt_col.)=0 %then %do; %put ERROR: 目标列名不能为空; %let &error_code.=1; %return; %end; /* 拆分列名列表,逐个校验 */ %let col_cnt=%sysfunc(countw(&trgt_col.)); %do j=1 %to &col_cnt.; %let col=%scan(&trgt_col.,&j.); %let len_col=%length(&col.); %do k=1 %to &len_col.; %let char=%substr(&col.,&k,1); %if %verify(&char.,&valid_chars.)>0 %then %do; %put ERROR: 目标列名&col.包含非法字符:&char.,仅允许字母和下划线; %let &error_code.=2; %return; %end; %end; %end; /* 所有校验通过 */ %put NOTE: 表名及列名格式均合法; %mend check_table;
主代码调用调整
在主程序中调用宏时,传入错误码参数,后续根据错误码控制流程:
/*******import mapping excel file********/ proc import datafile="/home/viadmin/casuser/mapping.xlsx" out= work.mapping dbms=xlsx replace; sheet=sheet1; run; /* update bank_key value */ data mapping; set mapping; if target_column='bank_key' then mapping='0'; if target_column='change_begin_date' then mapping='%SYSFUNC(DATETIME())'; if target_column='change_end_date' then mapping="'01JAN5999:00:00:00'DT"; if target_column='current_ind' then mapping='"Y"'; if target_column = "bank_status_desc" then delete; run; /**create list of source and target tables to be loaded***/ proc sql noprint; select distinct source_table into :source_table trimmed from mapping where source_table is not null; run; %put &source_table; proc sql noprint; select distinct target_table, catx(' ', mapping) into :target_table trimmed, :mapping_func trimmed from mapping; select target_column into :trgt_col separated by ' ' from mapping; select count(*) into :count trimmed from mapping; run; /* 调用校验宏,传入错误码参数 */ %check_table(error_code=chk_err); /* 根据错误码判断是否继续执行后续步骤 */ %if &chk_err.=0 %then %do; %createTable; proc sql noprint; select compress(put(max(BANK_KEY), best32.)) into :etls_maxkey trimmed from amlcore.&target_table; quit; /* %scdType2Loader; */ %end; %else %do; %put ERROR: 校验未通过,错误码=&chk_err.,终止后续流程; %end;
关键说明
- 合法字符校验:使用
%verify函数判断单个字符是否在合法集合中,返回值>0表示字符不在集合内(即非法) - 错误码机制:通过宏参数
error_code传递错误码变量名,宏内部修改该变量的值,主程序可直接读取 - 范围覆盖:新增目标表名和目标列名的校验,列名通过
countw拆分列表后逐个校验 - 空值处理:用
%length(&var.)=0判断宏变量是否为空,避免因宏变量未初始化导致的判断异常
内容的提问来源于stack exchange,提问作者Gujjar
相关产品推荐
相关产品推荐

