是否有T-SQL的标点符号等效项,例如[0-9]代表数字,[az]代表字母?


8

在T-SQL中是否存在[0-9][a-z]模式的等效项,可让我从包含标点的列中提取值?

例如:

Create Table #Test
(
Value   VarChar(10)
) 
Insert Into #Test
Values ('123a'), ('456b'), ('12ABC'),('AB!23'),('C?D789')

Select      *
From        #Test
Where       Value like '[0-9][0-9][0-9][a-z]'

这将返回值,其中前3个字符是介于0到9之间的数字,而最后一个字符将是介于a和z之间的字母,因此将返回123a456b而不会返回12ABC

我想知道标点符号是否等同于[0-9]数字和[a-z]字母,以便返回AB!23并返回C?D789

如果我可以使用正则表达式,则可以使用该表达式^[a-zA-Z0-9]*$来匹配字符串中的字母数字字符。

Where       Value like '^[a-zA-Z0-9]*$'

是否有等效的SQL?

我知道可以在RegEx中完成这种操作,但在T-SQL中需要它,因为我无法将任何自定义程序集加载到此服务器上,因此不能使用正则表达式。

实际列为varchar(200)。排序规则为Latin1_General_CI_AS。我正在使用SQL Server 2012 Standard Edition。


Answers:


12

在未来到精确的溶液中的最大的困难是在限定恰好字符是什么要被包括(或排除,取其方向更有意义的操作)。含义:

  • 我们是在谈论VARCHAR/ ASCII数据还是NVARCHAR/ Unicode数据?ASCII数据的标点符号列表取决于“代码页”,而“代码页”又取决于“排序规则”。(在此问题中,我们正在处理ASCII数据)。
  • 我们是在处理区分大小写还是不区分大小写的搜索?
  • 列设置为什么排序规则?排序规则将告诉我们代码页和区分大小写。(在这个问题我们正在处理Latin1_General_CI_AS
  • 是术语“标点符号”的意思只是标准的标点字符(例如.,;:,等),或者这是否意味着非字母数字字符?
  • 是否包含空格字符?
  • 是否包含控制字符?
  • 什么货币符号,如¢£¥,等?
  • 那么诸如©和的符号呢?
  • 什么字符被认为是“字母”?都是非英语字符如ÂÉÑßÞ包括?
  • 由于此问题与英国键盘有关(请参阅此问题的讨论),Æ/ æ字符如何?

为了帮助简化有关预期行为的清晰度,以下查询将显示Latin1字符集的所有256个字符(即代码页1252)以及@Shaneis 提出的解决方案的两个变体如何工作。第一个字段(标记为Latin1_General_CI_AS)显示了LIKE@Shaneis提出的条款(截至撰写本文时),第二个字段(标记为Latin1_General_100_BIN2)显示了一种修改形式,其中我覆盖了Collat​​ion以指定二进制数(即,以结尾的Collat​​ion _BIN2_BIN排序规则已弃用,因此,如果您可以访问_BIN2版本,请不要使用它们),这意味着我还需要添加A-Z范围以过滤出大写字母,因为当前的排序规则不区分大小写:

;WITH nums AS
(
  SELECT TOP (256) (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1) AS [Decimal]
  FROM   [master].[sys].[all_objects]
)
SELECT nm.[Decimal],
       CHAR(nm.[Decimal]) AS [Character],
       CASE WHEN CHAR(nm.[Decimal]) LIKE '%[^a-z0-9]%'
               THEN 'x' ELSE '' END AS [Latin1_General_CI_AS],
       CASE WHEN CHAR(nm.[Decimal]) LIKE '%[^a-z0-9A-Z]%' COLLATE Latin1_General_100_BIN2
               THEN 'x' ELSE '' END AS [Latin1_General_100_BIN2]
FROM   nums nm;

更新

应该提到的是,如果一个人确实在寻找被分类为“标点符号”(而不是“货币符号”,“数学符号”等)的字符,并且如果一个人不被禁止使用SQLCLR /加载自定义程序集(SQLCLR是SQL Server 2005引入的,并且我还没有遇到不允许这样做的充分理由,尤其是因为Azure SQL Database V12支持程序集SAFE),因此可以使用正则表达式,但是不能因为大多数人的缘故会猜到。

\w您可以指定要过滤的字符的Unicode类别,而不是使用正则表达式来构建功能更强的字符范围,甚至不使用类似的东西(表示任何“单词”字符),而无需使用诸如此类的东西。:

https://www.regular-expressions.info/unicode.html#category

您甚至可以指定要过滤的Unicode块,例如“ InBengali”或“ InDingbats”或“ InOptical_Character_Recognition”等:

https://www.regular-expressions.info/unicode.html#block

有许多为SQL Server创建RegEx函数的示例(尽管大多数示例未遵循SQLCLR最佳实践),或者您可以下载SQL#库的免费版本(由我创建),并按如下方式使用标量RegEx_IsMatch函数:

SQL#.RegEx_IsMatch(Unicode-String-Expression, N'\p{P}', 1, NULL)

\p{P}表达式表示\p= Unicode类别,并且{P}=所有标点符号(与特定类型的标点符号相反,例如“连接器标点符号”)。并且,“标点符号”类别包括所有语言的所有标点符号!您可以通过以下链接在Unicode.org网站上查看完整列表(该类别中当前有717个代码点):

http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AGeneral_Category%3DPunctuation%3A%5D

测试查询的更新版本如上图所示,包括使用另一场SQL#.RegEx_IsMatch\p{P},和跨代码页1252(即Latin1_General)的所有256个字符的所有3次测试的结果已在被张贴在PasteBin.com:

T-SQL查询和用于过滤字符类型的结果


更新
在相关讨论中提到了以下内容:

您已经对重音符号提出了很好的要求,因为它们是来自世界各地的酒店名称,所以名称中会包含重音符号,对于我的问题,我想将它们归类为有效的字母字符。

在这种情况下:

  1. Latin1字符集/代码页中包含11个非英语字符,它们与a-z范围不匹配。它们是:ð Ð Þ þ œ Œ š Š ž Ž Ÿ。这些需要添加到通配符中,虽然目前没有必要,但是添加起来不会有什么坏处,A-Z这样该模式在区分大小写的排序规则中也可以很好地工作。最终结果是:
    LIKE '%[^a-zA-Z0-9ðÐÞþœŒšŠžŽŸ]%'

  2. 考虑到该数据可以包含“来自世界各地的酒店名称”,因此我强烈建议将列的数据类型更改为,NVARCHAR以便可以存储所有语言的所有字符。保持这种状态VARCHAR存在极高的最终数据丢失风险,因为您只能代表基于拉丁语的语言,而对于那些提供了其他与拉丁语有关的字符的六个补充Unicode类别的语言,它们甚至还不能完全代表。


5

我可能对此有点简化了,但是,如果我们说删除了字母数字值后只剩下标点符号,那么下面的内容将搜索其中包含非字母数字字符的字符串。

Create Table #Test
(
Value   VarChar(10)
) 
Insert Into #Test
Values ('123a'), ('456b'), ('12ABC'),('AB!23'),('C?D789')

-- Original
Select      *
From        #Test
Where       Value like '[0-9][0-9][0-9][a-z]'

-- Non Alpha-numeric
SELECT * FROM #Test WHERE Value LIKE '%[^a-z0-9]%';

DROP TABLE #Test;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.