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。阐明匹配的目标(每个目标代码的二进制变量,或每个匹配目标的结果行)
  • 您必须对安装进行基准测试,以便在各种方法之间进行性能比较

    此示例代码是2a的一个模型。宏生成SQL案例以标记“任意匹配”条件。结果查询的代价很高,因为它需要为每一行使用一个规范化正则表达式,并且所有的case条件都必须失败,才能将某一行从结果集中排除

    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)