Sử dụng RegEx trong SQL Server


92

Tôi đang tìm cách thay thế / mã hóa văn bản bằng RegEx dựa trên cài đặt / thông số RegEx bên dưới:

RegEx.IgnoreCase = True     
RegEx.Global = True     
RegEx.Pattern = "[^a-z\d\s.]+"   

Tôi đã xem một số ví dụ trên RegEx, nhưng bối rối không biết làm thế nào để áp dụng nó theo cách tương tự trong SQL Server. Bất kỳ đề nghị sẽ là hữu ích. Cảm ơn bạn.


1
Hi hãy xem bài viết này: codeproject.com/Articles/42764/...
Mohsen

Ngoài ra còn bị phạt tiền TSQL + Windows API giải pháp tại Robyn Page và Phil Factor dựa trên VBScript.RegExp lớp, trong đó, tôi belieave, được vận chuyển trên tất cả các phiên bản Windows từ Windows 2000.
Julio Nobre

Nếu bạn hoàn toàn tích cực cần RegEx qua TSQL, một lựa chọn cho SQL Server 2016 và ở trên là dịch vụ sử dụng R .
Dave Mason

Câu trả lời:


103

Bạn không cần phải tương tác với mã được quản lý, vì bạn có thể sử dụng LIKE :

CREATE TABLE #Sample(Field varchar(50), Result varchar(50))
GO
INSERT INTO #Sample (Field, Result) VALUES ('ABC123 ', 'Do not match')
INSERT INTO #Sample (Field, Result) VALUES ('ABC123.', 'Do not match')
INSERT INTO #Sample (Field, Result) VALUES ('ABC123&', 'Match')
SELECT * FROM #Sample WHERE Field LIKE '%[^a-z0-9 .]%'
GO
DROP TABLE #Sample

Khi biểu thức của bạn kết thúc, +bạn có thể đi với'%[^a-z0-9 .][^a-z0-9 .]%'

CHỈNH SỬA : để làm rõ: SQL Server không hỗ trợ các biểu thức chính quy mà không có mã được quản lý. Tùy thuộc vào tình huống, LIKEtoán tử có thể là một tùy chọn, nhưng nó thiếu tính linh hoạt mà biểu thức chính quy cung cấp.


8
@MikeYoung, bạn nói đúng. Câu trả lời này giải quyết không chính xác bộ +định lượng như {1,2}khi nào nó nên coi nó như là {1, }. Đáng ngạc nhiên, điều này đã hiệu quả với OP.
Rubens Farias

2
Điều này sẽ không hoạt động trong máy chủ sql vì nó không hỗ trợ regex.
VVN

10
@VVN, LIKEkhông phải là regex (đó là cú pháp so khớp mẫu hạn chế hơn), vì vậy việc thiếu hỗ trợ regex không có nghĩa là điều này sẽ không hoạt động.
Charles Duffy

@RubensFarias sẽ không vui nếu cập nhật câu trả lời dựa trên nhận xét từ @ mike-young phải không?
Sudhanshu Mishra

8

Phiên bản sửa đổi một chút về câu trả lời của Julio.

-- MS SQL using VBScript Regex
-- select dbo.RegexReplace('aa bb cc','($1) ($2) ($3)','([^\s]*)\s*([^\s]*)\s*([^\s]*)')
-- $$ dollar sign, $1 - $9 back references, $& whole match

CREATE FUNCTION [dbo].[RegexReplace]
(   -- these match exactly the parameters of RegExp
    @searchstring varchar(4000),
    @replacestring varchar(4000),
    @pattern varchar(4000)
)
RETURNS varchar(4000)
AS
BEGIN
    declare @objRegexExp int, 
        @objErrorObj int,
        @strErrorMessage varchar(255),
        @res int,
        @result varchar(4000)

    if( @searchstring is null or len(ltrim(rtrim(@searchstring))) = 0) return null
    set @result=''
    exec @res=sp_OACreate 'VBScript.RegExp', @objRegexExp out
    if( @res <> 0) return '..VBScript did not initialize'
    exec @res=sp_OASetProperty @objRegexExp, 'Pattern', @pattern
    if( @res <> 0) return '..Pattern property set failed'
    exec @res=sp_OASetProperty @objRegexExp, 'IgnoreCase', 0
    if( @res <> 0) return '..IgnoreCase option failed'
    exec @res=sp_OAMethod @objRegexExp, 'Replace', @result OUT,
         @searchstring, @replacestring
    if( @res <> 0) return '..Bad search string'
    exec @res=sp_OADestroy @objRegexExp
    return @result
END

Bạn sẽ cần bật Quy trình tự động hóa Ole trong SQL:

exec sp_configure 'show advanced options',1; 
go
reconfigure; 
go
sp_configure 'Ole Automation Procedures', 1; 
go
reconfigure; 
go
sp_configure 'show advanced options',0; 
go
reconfigure;
go

2
BTW, việc phá hủy và tạo lại đối tượng regex nhanh hơn nhiều so với việc lưu vào bộ nhớ cache và sử dụng lại nó. Chúng tôi đã chạy 10.000 lượt so sánh với số lượng sử dụng lại đối tượng cao hơn đáng kể.
Zachary Scott

8

Bạn sẽ phải xây dựng một thủ tục CLR cung cấp chức năng regex, như bài viết này minh họa.

Hàm ví dụ của họ sử dụng VB.NET:

Imports System
Imports System.Data.Sql
Imports Microsoft.SqlServer.Server
Imports System.Data.SqlTypes
Imports System.Runtime.InteropServices
Imports System.Text.RegularExpressions
Imports System.Collections 'the IEnumerable interface is here  


Namespace SimpleTalk.Phil.Factor
    Public Class RegularExpressionFunctions
        'RegExIsMatch function
        <SqlFunction(IsDeterministic:=True, IsPrecise:=True)> _
        Public Shared Function RegExIsMatch( _
                                            ByVal pattern As SqlString, _
                                            ByVal input As SqlString, _
                                            ByVal Options As SqlInt32) As SqlBoolean
            If (input.IsNull OrElse pattern.IsNull) Then
                Return SqlBoolean.False
            End If
            Dim RegExOption As New System.Text.RegularExpressions.RegExOptions
            RegExOption = Options
            Return RegEx.IsMatch(input.Value, pattern.Value, RegExOption)
        End Function
    End Class      ' 
End Namespace

... và được cài đặt trong SQL Server bằng cách sử dụng SQL sau (thay thế '%' - các biến được phân tách bằng các biến tương đương thực tế của chúng:

sp_configure 'clr enabled', 1
RECONFIGURE WITH OVERRIDE

IF EXISTS ( SELECT   1
            FROM     sys.objects
            WHERE    object_id = OBJECT_ID(N'dbo.RegExIsMatch') ) 
   DROP FUNCTION dbo.RegExIsMatch
go

IF EXISTS ( SELECT   1
            FROM     sys.assemblies asms
            WHERE    asms.name = N'RegExFunction ' ) 
   DROP ASSEMBLY [RegExFunction]

CREATE ASSEMBLY RegExFunction 
           FROM '%FILE%'
GO

CREATE FUNCTION RegExIsMatch
   (
    @Pattern NVARCHAR(4000),
    @Input NVARCHAR(MAX),
    @Options int
   )
RETURNS BIT
AS EXTERNAL NAME 
   RegExFunction.[SimpleTalk.Phil.Factor.RegularExpressionFunctions].RegExIsMatch
GO

--a few tests
---Is this card a valid credit card?
SELECT dbo.RegExIsMatch ('^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$','4241825283987487',1)
--is there a number in this string
SELECT dbo.RegExIsMatch( '\d','there is 1 thing I hate',1)
--Verifies number Returns 1
DECLARE @pattern VARCHAR(255)
SELECT @pattern ='[a-zA-Z0-9]\d{2}[a-zA-Z0-9](-\d{3}){2}[A-Za-z0-9]'
SELECT  dbo.RegExIsMatch (@pattern, '1298-673-4192',1),
        dbo.RegExIsMatch (@pattern,'A08Z-931-468A',1),
        dbo.RegExIsMatch (@pattern,'[A90-123-129X',1),
        dbo.RegExIsMatch (@pattern,'12345-KKA-1230',1),
        dbo.RegExIsMatch (@pattern,'0919-2893-1256',1)

Đây là trong ASP cổ điển, nó có hỗ trợ không? Tôi nghĩ CLR chỉ dành cho các chức năng .NET, phải không?
Control Freak

4
Các thủ tục CLR được cài đặt vào môi trường SQL Server và có thể được gọi giống như bất kỳ thủ tục được lưu trữ nào khác hoặc hàm do người dùng xác định, vì vậy nếu Classic ASP có thể gọi một thủ tục được lưu trữ hoặc hàm do người dùng xác định, nó có thể gọi một thủ tục CLR.
mwigdahl

1
Mặc dù liên kết này có thể trả lời câu hỏi, nhưng tốt hơn hết bạn nên đưa các phần thiết yếu của câu trả lời vào đây và cung cấp liên kết để tham khảo. Các câu trả lời chỉ có liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi. - Từ xét
Federico Klez Culloca

Cảm ơn @FedericoklezCulloca. Đây là một câu trả lời cũ và tôi đã cập nhật nó cho phù hợp.
mwigdahl

@mwigdahl cảm ơn vì điều đó. Tôi thấy nó cũ, nhưng nó xuất hiện trong một hàng đợi xem xét :)
Federico Klez Culloca

7

Biểu thức chính quy trong sử dụng triển khai cơ sở dữ liệu SQL Server

Biểu thức chính quy - Mô tả
. Khớp bất kỳ một ký tự nào
* Khớp bất kỳ ký tự nào
+ Khớp ít nhất một phiên bản của biểu thức trước
^ Bắt đầu ở đầu dòng
$ Tìm kiếm ở cuối dòng
< Chỉ khớp nếu từ bắt đầu tại điểm này
> Chỉ khớp nếu từ dừng tại điểm này
\ n Khớp một dấu ngắt dòng
[] Khớp bất kỳ ký tự nào trong ngoặc
[^ ...] Khớp bất kỳ ký tự nào không được liệt kê sau ^
[ABQ]% Chuỗi phải bắt đầu bằng các chữ cái A, B hoặc Q và có thể có độ dài bất kỳ
[A B C D]% Chuỗi phải có độ dài từ hai trở lên và phải bắt đầu bằng A hoặc B và có C hoặc D là ký tự thứ hai
[ A-Z ]% Chuỗi có thể có độ dài bất kỳ và phải bắt đầu bằng bất kỳ chữ cái nào từ A đến Z
[A -Z0-9]% Chuỗi có thể có độ dài bất kỳ và phải bắt đầu bằng bất kỳ chữ cái nào từ A đến Z hoặc chữ số từ 0 đến 9
[^ AC]% Chuỗi có thể có độ dài bất kỳ nhưng không được bắt đầu bằng các chữ cái A đến C
% [AZ] Chuỗi có thể có độ dài bất kỳ và phải kết thúc bằng bất kỳ chữ cái nào từ A đến Z
% [% $ # @]% Chuỗi có thể có độ dài bất kỳ và phải chứa ít nhất một trong các ký tự đặc biệt kèm theo dấu ngoặc


5
SELECT * from SOME_TABLE where NAME like '%[^A-Z]%'

Hoặc một số biểu thức khác thay vì AZ


1

Một cách tiếp cận tương tự cho câu trả lời của @ mwigdahl, bạn cũng có thể triển khai .NET CLR trong C #, với mã như;

using System.Data.SqlTypes;
using RX = System.Text.RegularExpressions;

public partial class UserDefinedFunctions
{
 [Microsoft.SqlServer.Server.SqlFunction]
 public static SqlString Regex(string input, string regex)
 {
  var match = RX.Regex.Match(input, regex).Groups[1].Value;
  return new SqlString (match);
 }
}

Hướng dẫn cài đặt có thể được tìm thấy tại đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.