我在工作中遇到这样的问题:
列Code
的值类似于1000,1200,A1000,B1200,AAA,BBB等。目前它由空格分隔,有时由于数据输入不佳而多于一个空格。我正在尝试检查记录是否包含我感兴趣的代码。
Interested_Code
:1000或A1000或444或555或A555等。
我知道一个简单的解决方案from this answer:
A.CODE LIKE CAT('% ', T3.Interested_Code, ' %')
我已将前导和尾随空格附加到A.CODE
,以确保返回“完整”完全匹配。因为如果我只是做
A.CODE LIKE CAT('%', T3.Interested_Code, '%') or
A.CODE CONTAINS T3.Interested_Code
我会在包含代码= 1000
的行中得到代码= A1000
的误报,这会匹配部分代码,但不一定是正确的结果。
我的代码在上面工作,但它做了太多的测试并且非常慢。在PROC SQL中有更快或更智能的方法吗?主表大约是100k行,每行大约有10-20个代码。感兴趣的代码大约是8k值。感谢。
答案 0 :(得分:3)
您可以使用FINDW
或INDEXW
来查找"字" (默认情况下,用空格或类似的东西分隔)。这可能比你的解决方案更好,特别是因为你找不到
"1000 "
因为它不以空格开头,就像你一样。
proc sql;
create table final_codes as
select codes.*
from codes where exists (
select 1 from interested_codes
where findw(codes.code,trim(interested_codes.code)) > 0)
;
quit;
但是,这实际上是一个笛卡尔联接,非常慢。它必须加入所有可能的组合 - 8000次100,000,或有效8亿次临时行,然后再进行子集化。无论你做什么,它都不会那么快。
在数据步骤中执行此操作会更有效,特别是因为一旦找到匹配项就可以更轻松地停止。您可以将interested_codes表放入哈希表或临时数组中,然后根据您的匹配频率,可能会更快地搜索interested_codes表中的每个代码,或者相反,但两种方式都停止当你找到一个匹配(而不是做所有可能的组合)。
答案 1 :(得分:2)
尝试使用正则表达式:
data want;
set have;
where prxmatch('/^1000$/',strip(code));
run;
答案 2 :(得分:2)
有两个主要问题
解决方案的功能将是
您必须对安装进行基准测试,以便在各种方法之间进行性能比较。
此示例代码是2a的模型。宏构建一个SQL案例来标记“任何匹配”条件。结果查询很昂贵,因为它需要为每行标准化正则表达式,并且所有情况条件必须失败才能从结果集中排除行。
data have;
code = 'A 1000 1111 C333 555 A111 Z 999 B 222'; output;
code = 'ZZZZZ 1121'; output;
code = 'A 1000'; output;
code = 'AB1000'; output;
run;
%macro withAnyOf (data=have, out=want, targets=);
%local i qTarget N;
%let N = %sysfunc(countw(&targets,%str( )));
%put NOTE: &=N;
%do i = 1 %to &N;
%local clause&i;
%let qTarget = %sysfunc(quote(%qscan(&targets,&i,%str( ))));
%let clause&i = when indexw (calculated codeCleaned, &qTarget) then 1;
%put NOTE: &&clause&i;
%end;
proc sql;
create table &out(drop=codeCleaned) as
select
*
, ' ' || prxchange('s/([A-Z]) +/$1/',-1,code) || ' ' as codeCleaned
from &data
where
case
%do i = 1 %to &N;
&&clause&i
%end;
else 0
end
;
quit;
%mend;
options mprint;
%withAnyOf (targets=1000 A1000 444 555 A555)