T-SQL中的SQL Server正则表达式


127

是否有SP用于SQL Server的以T-SQL(无CLR,无扩展的纯T-SQL)编写的正则表达式库,并且可以与共享主机一起使用?

编辑:

  • 谢谢,我知道PATINDEXLIKExp_ sps和CLR解决方案
  • 我也知道这不是正则表达式的最佳选择,这个问题是理论上的:)
  • 减少的功能也可以接受

2
我也有这个问题。我知道数据库不是拥有此功能的最佳位置,但现实是其他解决方案需要SQL管理员权限才能重新配置服务器。不幸的是,我们的某些客户不会选择启用CLR等,因此我们只能使用纯数据库解决方案。
Paul Draper 2013年

@PaulDraper和xnagyg:为什么要排除SQLCLR?这是在查询中获取正则表达式的最合适方法。为何某些客户选择不启用CLR?我还没有遇到一个合理的理由。当然,我听到了“安全性”和“性能”,但这是虚假的原因,原因是不了解SQLCLR的工作方式以及如何对其进行限制。
所罗门·鲁茨基

3
@srutzky:大多数共享主机提供商不允许CLR。您应该向他们询问“安全性”和“性能” :)
xnagyg 2015年

@xnagyg当然,我可以问几个。但是,指出一个群体的行为并不能以任何方式解决该行为的“是否有正当理由” 的问题。所有这些共享的托管服务提供商都可能基于相同的误解来设置其策略,这很容易。而且,如果不出意外,一个简单的事实,并非所有的人禁止SQLCLR实际上支持那里的想法没有是一个问题不止存在是一个问题的想法,因为如果这些问题确实存在,该供应商允许SQLCLR将经历这些问题,将停止允许它。
所罗门·鲁兹基2015年

@xnagyg另外,我应该澄清一下,我所说的程序集是SAFE标记为EXTERNAL_ACCESS或未标记为或的UNSAFE(因为我确实理解为什么后两个权限集对于共享托管环境会造成问题)。Microsoft Azure SQL数据库V12(即2014年底的新版本)是一个共享环境,允许标有的程序集SAFE(并且FROM 0x...由于无法上传DLL而通过而不是从DLL 加载)。但是SAFE,这是其他非常有用的函数的正则表达式和LOTS所需的全部。
所罗门·鲁茨基

Answers:


77

如何在PATINDEX函数?

TSQL中的模式匹配不是一个完整的正则表达式库,但它为您提供了基础知识。

(摘自在线图书)

Wildcard  Meaning  
% Any string of zero or more characters.

_ Any single character.

[ ] Any single character within the specified range 
    (for example, [a-f]) or set (for example, [abcdef]).

[^] Any single character not within the specified range 
    (for example, [^a - f]) or set (for example, [^abcdef]).

7
至少十年来(SQL Server 2005+)LIKE支持所有PATINDEX功能。在那之前不知道...
TJ Crowder 2015年

1
但是,这不能让我指定与可变数量的ascii字母匹配的模式。%匹配0个或多个字符(无论如何),[...]仅匹配一个字符,并且两者之间没有任何匹配。
马丁·彼得斯

LIKE与PATINDEX> 0相同
逆向工程师,

21

如果有人对将正则表达式与CLR一起使用感兴趣,那么这里是一个解决方案。下面的函数(C#.net 4.5)如果匹配模式,则返回1,如果不匹配,则返回0。我用它来标记子查询中的行。SQLfunction属性告诉sql server,此方法是SQL Server将使用的实际UDF。将文件另存为dll,放在可以从Management Studio访问的位置。

// default using statements above
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Text.RegularExpressions;

namespace CLR_Functions
{   
    public class myFunctions
    {
        [SqlFunction]
        public static SqlInt16 RegexContain(SqlString text, SqlString pattern)
        {            
            SqlInt16 returnVal = 0;
            try
            {
                string myText = text.ToString();
                string myPattern = pattern.ToString();
                MatchCollection mc = Regex.Matches(myText, myPattern);
                if (mc.Count > 0)
                {
                    returnVal = 1;
                }
            }
            catch
            {
                returnVal = 0;
            }

            return returnVal;
        }
    }
}

在Management Studio中通过可编程性导入dll文件-程序集-新程序集

然后运行以下查询:

CREATE FUNCTION RegexContain(@text NVARCHAR(50), @pattern NVARCHAR(50))
RETURNS smallint 
AS
EXTERNAL NAME CLR_Functions.[CLR_Functions.myFunctions].RegexContain

然后,您应该可以通过将程序集存储在其中的数据库来完全访问该功能。

然后在这样的查询中使用:

SELECT * 
FROM 
(
    SELECT
        DailyLog.Date,
        DailyLog.Researcher,
        DailyLog.team,
        DailyLog.field,
        DailyLog.EntityID,
        DailyLog.[From],
        DailyLog.[To],
        dbo.RegexContain(Researcher, '[\p{L}\s]+') as 'is null values'
    FROM [DailyOps].[dbo].[DailyLog]
) AS a
WHERE a.[is null values] = 0

14

通过使用LIKE,可以使用一些基本的模式匹配,其中%匹配任意数字和字符组合,_匹配任意一个字符,[abc]可以匹配a,b或c ... MSDN网站上有更多信息。


5

如果您使用的是SQL Server 2016或更高版本,则可以sp_execute_external_script与R一起使用。它具有用于正则表达式搜索的功能,例如grepgrepl

这是电子邮件地址的示例。我将通过SQL Server数据库引擎查询一些“人员”,将这些人员的数据传递给R,让R决定哪些人员的电子邮件地址无效,然后让R将这些人员的子集传递回SQL Server。“人员”来自示例数据库中的[Application].[People][WideWorldImporters]。它们作为名为的数据帧传递到R引擎InputDataSet。R使用grepl函数和“ not”运算符(感叹号!)来查找哪些人的电子邮件地址与RegEx字符串搜索模式不匹配。

EXEC sp_execute_external_script 
 @language = N'R',
 @script = N' RegexWithR <- InputDataSet;
OutputDataSet <- RegexWithR[!grepl("([_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,4}))", RegexWithR$EmailAddress), ];',
 @input_data_1 = N'SELECT PersonID, FullName, EmailAddress FROM Application.People'
 WITH RESULT SETS (([PersonID] INT, [FullName] NVARCHAR(50), [EmailAddress] NVARCHAR(256)))

请注意,必须在SQL Server主机上安装适当的功能。对于SQL Server 2016,它称为“ SQL Server R服务”。对于SQL Server 2017,它已重命名为“ SQL Server机器学习服务”。

结束语 微软的SQL(T-SQL)实现没有对RegEx的本机支持。与使用CLR存储过程相比,此提议的解决方案对于OP可能并没有任何希望。但这确实提供了解决该问题的另一种方法。


4

如果其他任何人仍然在考虑这个问题,则http://www.sqlsharp.com/是一种免费的简便方法,可以将正则表达式CLR函数添加到数据库中。


3
再次,我提供的是CLR解决方案-不是OP要求的
工程师

10
@DaveBoltman:他在2008年问了这个问题。人们有时会搜索这个问题,并且遇到不想避免CLR的问题。这对我有所帮助,也许对他们有帮助。
约翰·费舍尔

当然,我确实同意@JohnFisher- 对于使用CLR的人来说,这一个有用的答案。但是在2015年,出于各种原因,我们仍然希望在SQL项目中使用仅SQL解决方案(无CLR),就像OP在2008年所做的那样。这一年并不重要:)例如,您的汽车电池已在1859年。但是您仍然想避免使用更现代的电池,例如100多年后发布的NiMH电池,由于各种原因(例如完全可以负担​​得起汽车):
反向工程师

2
@DaveBoltman:您错过了“人们有时会搜索此问题并遇到不想避免CLR的问题”这一部分。这是关键。
约翰·费舍尔

当然-您说得对@JohnFisher,您确实是这么说的。很高兴它对您有所帮助,而且我敢肯定它也会对其他人有所帮助
反向工程师

2

您可以使用OLE Automation使用VBScript正则表达式功能。这比创建和维护程序集的开销更好。请确保您通过注释部分,以获得对主要部分的更好的修改版本。

http://blogs.msdn.com/b/khen1234/archive/2005/05/11/416392.aspx

DECLARE @obj INT, @res INT, @match BIT;
DECLARE @pattern varchar(255) = '<your regex pattern goes here>';
DECLARE @matchstring varchar(8000) = '<string to search goes here>';
SET @match = 0;

-- Create a VB script component object
EXEC @res = sp_OACreate 'VBScript.RegExp', @obj OUT;

-- Apply/set the pattern to the RegEx object
EXEC @res = sp_OASetProperty @obj, 'Pattern', @pattern;

-- Set any other settings/properties here
EXEC @res = sp_OASetProperty @obj, 'IgnoreCase', 1;

-- Call the method 'Test' to find a match
EXEC @res = sp_OAMethod @obj, 'Test', @match OUT, @matchstring;

-- Don't forget to clean-up
EXEC @res = sp_OADestroy @obj;

如果SQL Server blocked access to procedure 'sys.sp_OACreate'...出现错误,请使用sp_reconfigure启用Ole Automation Procedures。(是的,很不幸,这是服务器级别的更改!)

有关该Test方法的更多信息,请点击此处

快乐编码


对不起,我知道这很老了,但是:为什么通过OLE的VBScript会比CLR“更好”?如果您只考虑维护,那您可能是对的,但是性能呢?
瑞典人

1
@swe通过“更好”,我指的是节省时间,这是因为为此目的创建和维护.NET程序集的开销。
James Poulose
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.