SAS PROC SQL:如何快速搜索变量是否包含完整的子字符串?
我在工作中遇到了这样的问题: 列SAS PROC SQL:如何快速搜索变量是否包含完整的子字符串?,sas,proc-sql,Sas,Proc Sql,我在工作中遇到了这样的问题: 列code的值类似于,1000、1200、A1000、B1200、AAA、BBB等。目前,它是由空格分隔的,有时由于数据输入不好,会有多个空格。我试图检查一个记录是否包含我感兴趣的代码 感兴趣的代码:1000或A1000或444或555或A555等 我知道一个简单的解决方案: 我在a.code后面加了一个前导空格和尾随空格,以确保返回“完整”的精确匹配。因为如果我这么做的话 A.CODE LIKE CAT('%', T3.Interested_Code, '%')
code
的值类似于,1000、1200、A1000、B1200、AAA、BBB等。目前,它是由空格分隔的,有时由于数据输入不好,会有多个空格。我试图检查一个记录是否包含我感兴趣的代码
感兴趣的代码:1000或A1000或444或555或A555等
我知道一个简单的解决方案:
我在a.code
后面加了一个前导空格和尾随空格,以确保返回“完整”的精确匹配。因为如果我这么做的话
A.CODE LIKE CAT('%', T3.Interested_Code, '%') or
A.CODE CONTAINS T3.Interested_Code
我将在包含code=A1000
的行中得到code=1000
的假阳性,这与部分代码匹配,但不需要正确的结果
我的代码在上面运行,但它做了太多的测试,速度非常慢。在PROC-SQL中是否有更快或更智能的方法?主表大约有10万行,每行大约有10-20个代码。感兴趣的代码是关于8k值的。谢谢。您可以使用
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乘以100000,或者实际上是8亿个临时行,然后才能将其子集。不管你做什么,它都不会那么快
在数据步骤中这样做会更有效率,特别是当您找到匹配项后,您可以更轻松地停止。您可以将感兴趣的代码表放入哈希表或临时数组中,然后根据您的匹配频率,搜索感兴趣的代码表中的每个代码可能会更快,反之亦然,但无论哪种方法,在找到匹配时都会停止(而不是进行所有可能的组合)。尝试使用正则表达式:
data want;
set have;
where prxmatch('/^1000$/',strip(code));
run;
主要有两个问题
2a。将记录标记为与任何记录匹配
2b。阐明匹配的目标(每个目标代码的二进制变量,或每个匹配目标的结果行)
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)
10-20个代码变量(
code1
到code20
),或在名为code
的单个列中包含10-20个代码?除了1个可能包含或不包含嵌入空格的代码值之外,列值是否包含任何其他信息?@Richard 10-20在我的主表中的一个名为“code”的列中包含代码。每个代码由1个或多个空格分隔。
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)