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

Sql server 对T-SQL中的字符范围使用通配符,sql-server,tsql,wildcard,sql-server-2016,Sql Server,Tsql,Wildcard,Sql Server 2016,我目前正在使用REPLACE替换以下可能在客户名称中找到的字符。然而,这样做很乏味 有人知道有没有一种方法可以使用列表格式(例如,通配符)来实现这一点:like[',','],而不是每次都写replace REPLACE(REPLACE(REPLACE(REPLACE(dname,'.',''),'`',''),'''',''),' ',' '))) 只需在函数中使用正则表达式,即可删除或包含所需的字符 e、 g 创建函数[dbo]。[AlphaCharactersOnly](@str Va

我目前正在使用
REPLACE
替换以下可能在客户名称中找到的字符。然而,这样做很乏味

有人知道有没有一种方法可以使用列表格式(例如,通配符)来实现这一点:
like[',',']
,而不是每次都写replace

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

只需在函数中使用正则表达式,即可删除或包含所需的字符

e、 g

创建函数[dbo]。[AlphaCharactersOnly](@str VarChar(MAX))
返回VarChar(最大值)
作为
开始
将@strKeep声明为varchar(最大值)
设置@strKeep='%[^^a-z]%
而PatIndex(@strKeep,@str)>0
设置@str=Stuff(@str,PatIndex(@strKeep,@str),1,,)
返回@str

结束

您只需在函数中使用正则表达式,即可删除或包含所需的字符

e、 g

创建函数[dbo]。[AlphaCharactersOnly](@str VarChar(MAX))
返回VarChar(最大值)
作为
开始
将@strKeep声明为varchar(最大值)
设置@strKeep='%[^^a-z]%
而PatIndex(@strKeep,@str)>0
设置@str=Stuff(@str,PatIndex(@strKeep,@str),1,,)
返回@str

结束

我们不知道版本,但如果您仅为2016年+
翻译
可能会在这里很好地工作:

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

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

您仍然需要在最左边的字符上使用
REPLACE
,以及双空格。

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

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

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

您仍然需要在最左边的字符上使用
REPLACE
,并且使用双空格。

对于这种类型的东西,我会使用。它不是标量,100%基于集合,而且速度很快

要从此字符串中删除非字母数字,请执行以下操作:

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

仅返回值表中的数字:

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
返回:

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

对于这种类型的事情我会同意。它不是标量,100%基于集合,而且速度很快

要从此字符串中删除非字母数字,请执行以下操作:

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

仅返回值表中的数字:

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
返回:

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\u General*
,它反过来使用代码页1252作为
VARCHAR
数据)

也就是说,名称中有许多字符是有效的(通常是字母,但也有连字符和逗号),还有许多字符是无效的。尝试指定任一组,即使是字符类中的一系列字符(即
[…]
)是一种可能需要在每次有新产品出现时进行更新的产品

处理这个问题的一个简单方法是使用正则表达式(即RegEx和no,
LIKE
PATINDEX
函数的
[…]
通配符不是正则表达式,不管有多少人这样引用它).SQL Server本机不支持正则表达式,但您可以通过SQLCLR获得该功能,该功能适用于从2005年开始的所有版本的所有prem版本(包括Linux上的SQL Server)和Azure SQL数据库管理实例;它仅在常规Azure SQL数据库和AWS SQL Server RDS(从2017年开始)上不可用。获取正则表达式的一个简单方法是下载并安装我创建的SQLCLR库(大多数正则表达式函数都是免费版本,包括我将在下面使用的函数)

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

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

  • [^…]
    =查找与此列表中的字符不匹配的任何单个字符
  • \p{L}
    =匹配任何分类为“字母”的字符(在任何语言中,这就是为什么它可以工作的原因)
  • ,-
    =匹配逗号、空格和连字符。由于连字符在字符类中用于指示范围,因此如果要用作文字连字符,则它们必须是第一个或最后一个字符
这就引出了下面的例子:

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
当然,这仍然给我们留下了一个没有其他答案(正确)解决的问题:将多个空间转换为单个空间

在问题中,您有一个
REPLACE
设置,用于将两个空格转换为单个空格。只有在只有两个空格的情况下,该设置才会起作用。如果有三个或更多空格,则它仅转换每组两个空格,这仍然会给您留下多个空格。例如:

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”空格测试都留下了两个空格,而“5”空格测试留下了三个空格

这里是正则表达式非常适合的另一种操作类型。您可以指定一个模式来匹配“两个或多个空间”,然后它将处理任意数量的空间,并用单个空间替换它匹配的任何内容,无论是2、3还是27个空间。我们可以使用
\s{2,}
模式,这意味着“两个或多个空格字符”,或
\s\s+
,表示“一个空格字符后跟一个或多个空格字符”

例如,如果我们从上一个正则表达式测试的输出开始,我们可以执行以下操作: