在 T-SQL 中对字符范围使用通配符
Posted
技术标签:
【中文标题】在 T-SQL 中对字符范围使用通配符【英文标题】:Using Wildcard For Range of Characters In T-SQL 【发布时间】:2019-08-16 10:09:46 【问题描述】:我目前正在使用REPLACE
替换以下可能在客户名称中找到的字符。但是,这样做很乏味。
有谁知道是否有办法使用列表格式来做到这一点,例如,像这样的通配符:LIKE ['.',',']
,而不是每次都写替换?
REPLACE(REPLACE(REPLACE(REPLACE(dname,'.',''),'`',''),'''',''),' ',' ')))
【问题讨论】:
你正在使用哪个 dbms (mysql, postgresql, tsql / sql-server, oracle)? @SebastianBrosch 我正在使用 T-SQL @user3396351 清理此数据的最佳位置是客户端应用程序,而不是 T-SQL。也就是说,SQL Server 2016 及更高版本允许您使用 R 和 Python 脚本。您可以使用 R 或 Python 脚本通过简单的正则表达式来清理名称,或使用文本处理和数据清理包,如 janitor 什么版本的 SQL Server?如果你是 2016 年,你有TRANSLATE
,这可能会让这更容易。
直到 SQL SERVER 2017 才引入 TRANSLATE
【参考方案1】:
我们不知道版本,但如果你只有 2016 年以上,TRANSLATE
可能在这里工作得很好:
DECLARE @ReplaceChars varchar(50) = '.''`()[]!"£$%^&*-=_+';
SELECT REPLACE(REPLACE(TRANSLATE(YourColumn, @ReplaceChars, REPLICATE(LEFT(@ReplaceChars, 1), LEN(@ReplaceChars)),LEFT(@ReplaceChars,1),''),' ',' ')
FROM ...
你仍然需要在最左边的字符上使用REPLACE
,不过还有两个空格。
【讨论】:
我相信这会起作用,但由于某种原因,它说'TRANSLATE' is not a recognized built-in function name.
我在 SSMS 17 上运行 SQL Server 2016,我在网上进行了研究,显然其他人在使用@987654325 时也遇到了同样的问题@在SSMS17上
这不是 SSMS 问题,@user3396351。 SSMS 对查询在数据引擎上的行为方式没有影响;它纯粹是一个交互和表示层。您的数据库处于什么兼容级别?它必须是 130 或更高。
@user3396351 SSMS 只是一个客户端工具。它不会影响数据库中可以使用或不能使用的内容
@Larnu 我当前的兼容级别设置为 110
然后@user3396351 是你的问题。 110 是 SQL Server 2012 级别,TRANSLATE
在那里不起作用。如果您无法更改级别,您将返回嵌套的 REPLACE
语句。【参考方案2】:
对于这种类型的事情,我会选择PatExclude8K。它不是标量的,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
【讨论】:
【参考方案3】:如果您使用客户名称,那么您真的应该使用 NVARCHAR
而不是 VARCHAR
,因为您不能保证名称只会包含美国英文字符(即“A”-“Z”)加上一些什锦重音字符(我假设您使用的是默认排序规则 *Latin1_General*
,而 VARCHAR
数据又使用代码页 1252)。
也就是说,有 很多 字符在名称中是有效的(通常是字母,但也有连字符和逗号),而 很多 字符是无效的.尝试指定任一组,即使是字符类中的一系列字符(即[...]
),每次出现新字符时都可能需要更新。
处理此问题的一种简单方法是使用正则表达式(即 RegEx,不,LIKE
和 PATINDEX
函数的[...]
通配符不是正则表达式,不不管有多少人这样称呼它)。 SQL Server 本身不支持 RegEx,但您可以通过 SQLCLR 获得该功能,该功能适用于从 2005 开始的所有版本的所有本地版本(包括 Linux 上的 SQL Server)和 Azure SQL 数据库托管实例;它仅在常规 Azure SQL 数据库和 AWS SQL Server RDS(从 2017 版开始)上不可用。获取 RegEx 的一个简单方法是下载并安装 SQL#,这是我创建的一个 SQLCLR 库(大部分 RegEx 函数都在免费版本中,包括我将在下面使用的)。
正则表达式不仅可以处理复杂的模式(比我们在这里处理的要复杂得多),而且它们还允许我们指定 Unicode“类别”。对于这种特殊情况,我们只需要使用“字母”类别,其中包括大写、小写和其他形式的字母。单独使用这个类别也会删除连字符和逗号,因为我们可能不想这样做(因为它们在名称中是有效的),我们可以轻松地将它们重新添加。
我们将使用的表达式是:[^\pL, -]
。这个模式读作:
[^...]
= 找到与此列表中的字符不匹配的任何单个字符
\pL
= 匹配任何归类为“字母”的字符(在任何语言中,这就是为什么这样有效)
, -
= 匹配逗号、空格和连字符。由于连字符在字符类中用于表示范围,因此如果要用作文字连字符,它们必须是第一个字符或最后一个字符。
这将我们带到以下示例:
SELECT SQL#.RegEx_Replace4k(
N'a .` ''b$c d ef-ghi,jr. ꓤ ඖ ל ؼ ញ z', -- string to modify
N'[^\pL, -]', -- 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
以将两个空格转换为一个空格。这只有在 only 两个空格的情况下才有效。如果有三个或更多空格,那么它只会转换每两个一组,这仍然会给您留下多个空格。例如:
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”空格测试留下三个空格。
这是 RegEx 非常适合的另一种操作类型。您可以指定一个模式以匹配“两个或多个空格”,然后它将处理任意数量的空格并将匹配的任何内容替换为单个空格,无论是 2、3 还是 27 个空格。我们可以使用\s2,
表示“两个或多个空白字符”或\s\s+
表示“一个空白字符后跟一个或多个空白字符”的模式。
例如,如果我们从上一个 RegEx 测试的输出开始,我们可以执行以下操作:
SELECT SQL#.RegEx_Replace4k(
N'a bc d ef-ghi,jr ꓤ ඖ ל ؼ ញ z', N'\s2,',
N' ',
-1, 1, NULL);
--a bc d ef-ghi,jr ꓤ ඖ ל ؼ ញ z
【讨论】:
【参考方案4】:您可以简单地在函数中使用正则表达式来删除或包含您想要的字符。
例如
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
【讨论】:
标量函数和WHILE
的组合可能会导致查询的性能很差。以上是关于在 T-SQL 中对字符范围使用通配符的主要内容,如果未能解决你的问题,请参考以下文章
T-SQL 转义select …. like中的特殊字符(百分号)