T-SQL 中的复杂正则表达式
Complex RegEx in T-SQL
我最近开始在我的查询中使用 RegEx 作为条件,但似乎 T-SQL 对官方语法的支持有限。
例如,我想测试一个字符串作为 00:00 和 23:59 之间的时间是否有效,一个好的 RegEx 表达式将是 "([0-1][0 -9]|[2][0-3]):([0-5][0-9])":
select iif('16:06' like '([0-1][0-9]|[2][0-3]):([0-5][0-9])', 'Valid', 'Invalid')
.. 失败并输出“无效”。我是否理解 T-SQL 无法处理分组和条件 (|)?我懒洋洋地使用了一个简化的 RegEx,它没有正确测试字符串——我对此非常不满意:
select iif('16:06' like '[0-2][0-9]:[0-5][0-9]', 'Valid, 'Invalid')
.. returns“有效”,但也会将字符串“28:06”视为有效。
我知道我可以添加进一步的检查来全面检查它是否是一个有效的时间字符串,但我更愿意充分利用 RegEx。
简单地问:我只是做错了或想错了这是一个限制,如果是的话 - 我如何在 T-SQL 中使用正确的 RegEx?
您可以使用以下逻辑:
SELECT IIF('16:06' LIKE '[01][0-9]:[0-5][0-9]' OR
'16:06' LIKE '2[0-3]:[0-5][0-9]', 'Valid', 'Invalid');
第一个 LIKE
表达式匹配 00:00
到 19:59
,第二个 LIKE
匹配 20:00
到 23:59
。如果 SQL 服务器支持完整的正则表达式,我们可以只使用一个带有交替的正则表达式。
用于 LIKE and PATINDEX is much more limited than what's commonly known as Regular Expressions 的模式语法。
在标准中 SQL 它实际上只有 2 个特殊字符。
%
: wildcard for 0 or more characters
_
: any 1 character
并且 T-SQL 在语法中添加了字符 class [...]
。
但是要测试字符串是否包含时间,使用 LIKE
可能很笨拙。
在 MS Sql 服务器中,可以使用 TRY_CONVERT or TRY_CAST 功能。
他们将 return NULL 表示转换为数据类型失败。
select IIF(TRY_CAST('16:06' AS TIME) IS NOT NULL, 'Valid', 'Invalid')
这将 return 'Valid' 用于“23:59”,但 'Invalid' 用于“24:00”
我建议使用 SQLCLR 编写用户定义的函数。由于 .Net 支持 Regex,您可以将其移植到 T-SQL。 Google中的第一个link给出了this implementation,但可能还有其他(更好的)实现。
警告 - 使用 SQLCLR 需要更高的权限,如果未正确实施,可能会导致安全问题或性能问题甚至 SQL 服务器的稳定性问题。但是,如果您知道自己在做什么,这可能会显着增强 T-SQL 特定于您的用例。
我最近开始在我的查询中使用 RegEx 作为条件,但似乎 T-SQL 对官方语法的支持有限。
例如,我想测试一个字符串作为 00:00 和 23:59 之间的时间是否有效,一个好的 RegEx 表达式将是 "([0-1][0 -9]|[2][0-3]):([0-5][0-9])":
select iif('16:06' like '([0-1][0-9]|[2][0-3]):([0-5][0-9])', 'Valid', 'Invalid')
.. 失败并输出“无效”。我是否理解 T-SQL 无法处理分组和条件 (|)?我懒洋洋地使用了一个简化的 RegEx,它没有正确测试字符串——我对此非常不满意:
select iif('16:06' like '[0-2][0-9]:[0-5][0-9]', 'Valid, 'Invalid')
.. returns“有效”,但也会将字符串“28:06”视为有效。
我知道我可以添加进一步的检查来全面检查它是否是一个有效的时间字符串,但我更愿意充分利用 RegEx。
简单地问:我只是做错了或想错了这是一个限制,如果是的话 - 我如何在 T-SQL 中使用正确的 RegEx?
您可以使用以下逻辑:
SELECT IIF('16:06' LIKE '[01][0-9]:[0-5][0-9]' OR
'16:06' LIKE '2[0-3]:[0-5][0-9]', 'Valid', 'Invalid');
第一个 LIKE
表达式匹配 00:00
到 19:59
,第二个 LIKE
匹配 20:00
到 23:59
。如果 SQL 服务器支持完整的正则表达式,我们可以只使用一个带有交替的正则表达式。
用于 LIKE and PATINDEX is much more limited than what's commonly known as Regular Expressions 的模式语法。
在标准中 SQL 它实际上只有 2 个特殊字符。
%
: wildcard for 0 or more characters
_
: any 1 character
并且 T-SQL 在语法中添加了字符 class [...]
。
但是要测试字符串是否包含时间,使用 LIKE
可能很笨拙。
在 MS Sql 服务器中,可以使用 TRY_CONVERT or TRY_CAST 功能。 他们将 return NULL 表示转换为数据类型失败。
select IIF(TRY_CAST('16:06' AS TIME) IS NOT NULL, 'Valid', 'Invalid')
这将 return 'Valid' 用于“23:59”,但 'Invalid' 用于“24:00”
我建议使用 SQLCLR 编写用户定义的函数。由于 .Net 支持 Regex,您可以将其移植到 T-SQL。 Google中的第一个link给出了this implementation,但可能还有其他(更好的)实现。
警告 - 使用 SQLCLR 需要更高的权限,如果未正确实施,可能会导致安全问题或性能问题甚至 SQL 服务器的稳定性问题。但是,如果您知道自己在做什么,这可能会显着增强 T-SQL 特定于您的用例。