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+
,表示“一个空格字符后跟一个或多个空格字符”
例如,如果我们从上一个正则表达式测试的输出开始,我们可以执行以下操作: