1

在 T-SQL 中,如何检查一个字符串是否包含两个或多个相似字符?

我的列包含 nvarchar 的手机号码,可能是“5512111445”、“6612888445”或隐藏号码,如“5512zzz44x”

我有一个用户输入的搜索模式,它可能是“xx12yyy4zx”,我想将所有匹配的数字返回到这个模式,其中 x、y、z 代表任何数字,但如果它重复,它将代表相同的数字。例如,前面的模式应该返回上面列出的所有数字。

xx 是类似的数字,如 55 或 66.. 而 xy 是不同的数字,如 45 或 67..

如何才能做到这一点?

4

2 回答 2

2

您可以将掩码和数字中的每个字符旋转到列中,然后单独对掩码进行分组,然后是掩码 + 编号。在此方法中,5512111445 和 6612888445 与掩码 xx12yyy4yz 不匹配,因为掩码中的 y 未映射到唯一数字。但是,手机号码 5512111415 和 6612888485 匹配掩码 xx12yyy4yz,手机号码 5512zzz44x 也是如此。

--declare @mobileNums varchar(10)='5512111445'; --no match because @mask y maps to different values
--declare @mobileNums varchar(10)='6612888445'; --no match because @mask y maps to different values
--declare @mobileNums varchar(10)='5512111415'; --no match because @mask x should not equal @mask z
--declare @mobileNums varchar(10)='6612888485'; --matches
--declare @mobileNums varchar(10)='8812888485'; --no match because @mask x should not equal @mask y
--declare @mobileNums varchar(10)='5512zzz44x'; --matches because z and x are both hidden and different
--declare @mask varchar(10)='xx12yyy4yz';

declare @mobileNums varchar(10)='3211zyy'; -- no match because @mask y <> @mask z, but @mobileNums y = y
declare @mask varchar(10)='3211yxz';

declare @t table(n char, m char);
declare @i int=1;

while @i<=LEN(@mobileNums) begin
    insert into @t values (SUBSTRING(@mobileNums,@i,1), SUBSTRING(@mask,@i,1));
    set @i+=1;
end

if exists(
    -----------------------------------------------------------------------------
    -- Group by m
    select
    m, c=count(m)
    from @t
    where ISNUMERIC(n)=0 and ISNUMERIC(m)=0
    group by m
    except
    select
    m, c=count(m+n)
    from @t
    where ISNUMERIC(n)=0 and ISNUMERIC(m)=0
    group by m,n

    union

    select
    m, c=count(m)
    from @t
    where ISNUMERIC(n)=0 and ISNUMERIC(m)=1
    group by m
    except
    select
    m, c=count(m+n)
    from @t
    where ISNUMERIC(n)=0 and ISNUMERIC(m)=1
    group by m,n

    union

    select
    m, c=count(m)
    from @t
    where ISNUMERIC(n)=1 and ISNUMERIC(m)=0
    group by m
    except
    select
    m, c=count(m+n)
    from @t
    where ISNUMERIC(n)=1 and ISNUMERIC(m)=0
    group by m,n

    union

    select
    m, c=count(m)
    from @t
    where ISNUMERIC(n)=1 and ISNUMERIC(m)=1
    group by m
    except
    select
    m, c=count(m+n)
    from @t
    where ISNUMERIC(n)=1 and ISNUMERIC(m)=1
    group by m,n

    union

    -----------------------------------------------------------------------------
    -- Group by n

    -- Add a rule that no numeric @mobileNums digit can correspond to more than one alpha @mask character
    select
    n, c=count(m)
    from @t
    where ISNUMERIC(n)=1 and ISNUMERIC(m)=0
    group by n
    except
    select
    n, c=count(m+n)
    from @t
    where ISNUMERIC(n)=1 and ISNUMERIC(m)=0
    group by m,n 

    union

    -- For GROUP BY n, include the three remaining combinations of ISNUMERIC(n) and ISNUMERIC(m)
    select
    n, c=count(m)
    from @t
    where ISNUMERIC(n)=0 and ISNUMERIC(m)=0
    group by n
    except
    select
    n, c=count(m+n)
    from @t
    where ISNUMERIC(n)=0 and ISNUMERIC(m)=0
    group by m,n    

    union

    select
    n, c=count(m)
    from @t
    where ISNUMERIC(n)=0 and ISNUMERIC(m)=1
    group by n
    except
    select
    n, c=count(m+n)
    from @t
    where ISNUMERIC(n)=0 and ISNUMERIC(m)=1
    group by m,n 

)
select patMatch='False'
else 
select patMatch='True';

编辑- 添加一个规则,没有数字 @mobileNums 数字可以对应多个字母 @mask 字符

编辑- 对于GROUP BY n,包括 ISNUMERIC(n) 和 ISNUMERIC(m) 的其余三个组合

编辑- 删除第八个UNION

于 2012-04-17T05:30:10.340 回答
2

我不会编写整个代码,因为它会很乏味,但我认为这可以让你开始。

  1. 将搜索模式转换为类似模式,将所有字母字符替换为下划线。这减少了您必须搜索的行数,但仍然可以让您筛选很多。
  2. 对于模式中的每个字符,过滤与模式匹配的行。“5512zzz44x”的示例:
    1. 以“z”开头:
      • “5512zzz44x”->“5512zzz44_”
      • 要么循环遍历结果,每次通过过滤掉行,要么生成动态 SQL,然后在创建整个事物后执行:
      • “5512zzz44_”->... mobile_num like '551200044_' or mobile_num like '551211144_' ... or mobile_num_like '551299944_'
    2. 下一个字符:'x':
      • “5512zzz44x”->“5512___44x”
      • (按照上面 2.1 的模式)

这个想法是逐步过滤掉结果,直到只剩下与原始模式匹配的#。

可能有更有效的方法来做到这一点。如果部署 CLR 是一种选择,那么使用 CLR 和正则表达式执行此操作可能是一个更好的主意。

于 2012-04-17T01:09:06.727 回答