对 T-SQL 中的字符范围使用通配符

Using Wildcard For Range of Characters In T-SQL

我目前正在使用 REPLACE 替换客户姓名中可能出现的以下字符。但是,这样做很乏味。

有人知道是否有办法使用列表格式来做到这一点,例如,像这样的通配符:LIKE ['.',','] 而不是每次都写替换?

REPLACE(REPLACE(REPLACE(REPLACE(dname,'.',''),'`',''),'''',''),'  ',' ')))

您可以简单地在函数中使用正则表达式来删除或包含您想要的字符。

例如

<pre>Create Function [dbo].[AlphaCharactersOnly](@str VarChar(MAX)) Returns VarChar(MAX) AS Begin Declare @strKeep as varchar(MAX) Set @strKeep = '%[^ ^a-z]%' While PatIndex(@strKeep, @str) > 0 Set @str = Stuff(@str, PatIndex(@strKeep, @str), 1, '') Return @str End</pre>

我们不知道版本,但如果您只有 2016 年以上,TRANSLATE 可能会在这里工作得很好:

DECLARE @ReplaceChars varchar(50) = '.''`(){}[]!"£$%^&*-=_+';

SELECT REPLACE(REPLACE(TRANSLATE(YourColumn, @ReplaceChars, REPLICATE(LEFT(@ReplaceChars, 1), LEN(@ReplaceChars)),LEFT(@ReplaceChars,1),''),'  ',' ')
FROM ...

你仍然需要在最左边的字符上使用 REPLACE,不过还要使用双空格。

对于这种类型的事情,我会选择 PatExclude8K。它不是标量,100% 基于集合并且速度极快。

要从此字符串中删除非字母数字:

SELECT f.* FROM dbo.PatExclude8K('ABC123!!!   ???','[^A-Z0-9]') AS f;

Returns: ABC123

Return 仅来自值 [=​​29=]:

的数字
DECLARE @table TABLE (someid INT IDENTITY, somestring VARCHAR(100));
INSERT @table (somestring) 
SELECT TOP (10) NEWID() FROM sys.all_columns;

SELECT t.someid, t.somestring, pe.NewString
FROM  @table AS t
CROSS APPLY dbo.PatExclude8K(t.somestring,'[^0-9]') AS pe

Returns:

someid      somestring                                NewString
----------- ----------------------------------------- ---------------------------
1           2FEF1D43-1A85-456D-BF9E-B329AD64A980      2143185456932964980
2           EB73205F-84C8-407E-8D4F-66FAFD1F556B      7320584840784661556
3           5BEA68B1-783B-4F57-A24D-CF110ADECFEA      568178345724110
4           FC7466E3-5CB8-4DDD-B7F0-30A539DF7C02      746635847030539702
5           800E3AC3-257F-4FF5-B7EE-E6B9268B5608      80033257457692685608
6           A1C33269-48EC-4100-A691-0EA9F2C55E21      1332694841006910925521
7           9C19F844-FE71-40BE-BFFF-276FE344B171      9198447140276344171
8           08529640-E77E-44AD-93A9-E69CE92AF1BD      08529640774493969921
9           FBADC1AE-ED96-4A0E-B106-C6C34E34A612      1964010663434612
10          7E52CFC5-025E-431B-99C1-589E957726B5      75250254319915899577265

如果您使用的是客户名称,那么您确实应该使用 NVARCHAR 而不是 VARCHAR,因为您不能保证名称只会包含美国英语字符(即 "A" - "Z") 加上一些重音字符(我假设您使用的是默认排序规则 *Latin1_General*,它又将代码页 1252 用于 VARCHAR 数据)。

也就是说,很多 字符在名称中有效(通常是字母,但也有连字符和逗号),很多 的无效字符。尝试指定任一组,即使是字符 class(即 [...])中的一系列字符,每次出现新字符时都可能需要更新。

处理这个问题的一个简单方法是使用正则表达式(即 RegEx,不,LIKEPATINDEX 函数的 [...] 通配符是 not 正则表达式,不管有多少人这样称呼它)。 SQL Server 本身不支持 RegEx,但您可以通过 SQLCLR 获得该功能,它适用于所有本地版本(包括 SQL Server on Linux)从 2005 开始的所有版本,以及 Azure SQL 数据库托管实例;它仅在常规 Azure SQL 数据库和 AWS SQL 服务器 RDS(从 2017 版开始)上不可用。获取 RegEx 的一种简单方法是下载并安装 SQL#,这是我创建的一个 SQLCLR 库(大多数 RegEx 函数都在免费版本中,包括我将在下面使用的内容)。

正则表达式不仅可以处理复杂的模式(比我们在这里处理的要复杂得多),而且它们还允许我们指定 Unicode "categories"。对于这种特殊情况,我们只需要使用 "Letter" 类别,它包括大写、小写和其他形式的字母。单独使用此类别也将删除连字符和逗号,并且由于我们可能不想这样做(因为它们在名称中有效),我们可以轻松地将它们添加回去。

我们将使用的表达式是:[^\p{L}, -]。此模式读作:

  • [^...] = 查找匹配此列表中的字符的任何单个字符
  • \p{L} = 匹配任何归类为 "Letter" 的字符(在 any 语言中,这就是为什么这有效)
  • , - = 匹配逗号、space 和连字符。由于连字符在字符 classes 中用于指示范围,因此如果要用作文字连字符,则它们必须是第一个或最后一个字符。

这给我们带来了以下示例:

SELECT SQL#.RegEx_Replace4k(
            N'a    .`     ''b$c   d  ef-ghi,jr. ꓤ ඖ  ל ؼ ញ z', -- string to modify
            N'[^\p{L}, -]',   -- regular expression (pattern)
            N'',              -- replacement
            -1,               -- number of occurrences to replace (-1 = unlimited)
            1,                -- character position to start at
            NULL              -- RegEx options (such as case-insensitive, multi-line, etc)
       );

 --a         bc   d  ef-ghi,jr ꓤ ඖ  ל ؼ ញ z

当然,这仍然给我们留下了一个没有其他答案(正确)解决的问题:将多个 space 转换为单个 space。

在问题中,您设置了一个 REPLACE 来将两个 space 转换为一个 space。只有 只有 两个 space 才有效。如果有三个或更多 spaces,那么它只会转换每两个一组,这仍然会给您留下多个 spaces。例如:

SELECT REPLACE(N'a   b', N'  ', N' ') AS [3 spaces],
       REPLACE(N'a    b', N'  ', N' ') AS [4 spaces],
       REPLACE(N'a     b', N'  ', N' ') AS [5 spaces];

/*
3 spaces    4 spaces    5 spaces
a  b        a  b        a   b
*/

如您所见,“3”和“4”space 测试都留下了两个 space,而“5”space 测试留下了三个 spaces.

这是 RegEx 非常适合的另一种操作。您可以指定一个匹配 "two or more spaces" 的模式,然后它将处理任意数量的 space 并将匹配的任何内容替换为单个 space,无论是 2、3 还是 27 space秒。我们可以使用 \s{2,} 表示 "two or more white-space characters" 或 \s\s+ 表示 "a white-space character followed by one-or-more white-space characters".

的模式

例如,如果我们从之前的RegEx测试的输出开始,我们可以这样做:

SELECT SQL#.RegEx_Replace4k(
           N'a         bc   d  ef-ghi,jr ꓤ ඖ  ל ؼ ញ z', N'\s{2,}',
           N' ',
           -1, 1, NULL);

--a bc d ef-ghi,jr ꓤ ඖ ל ؼ ញ z