正則表達式在文本查詢方面,不管是速度還是功能,都十分強大。雖然SQL Server數據庫可以執行模糊查詢(像like子句)和全文查詢(Fulltext search),但是這兩個子句只能查詢簡單的模式,無法應對復雜的查詢需求。這是因為SQL Server沒有執行正則表達式的內置函數,無法直接執行正則查找。我們可以創建CLR標量函數,在函數中調用正則表達式,把CLR函數發布到SQL Server數據庫中,這樣,就可以通過TSQL腳本調用CLR函數來執行復雜的正則查詢和匹配。
一,Regex類
Regex類用於表示一個正則表達式,執行匹配、替換和拆分操作,Regex類有五大方法:
- IsMatch():是否匹配到正則
- Match():返回正則的第一個匹配
- Matches():返回正則的全部匹配
- Replace():把匹配正則表達式的文本替換掉
- Split():把輸入文本拆分,拆分的邊界是匹配正則表達式的文本
1,創建Regex 對象
創建Regex對象,並指定正則選項(忽略大小寫):
Regex re = new Regex("(?<=\"UserID\":\").*?(?=\")", RegexOptions.IgnoreCase); string mat = re.Match(input_text).Value;
也可以直接使用靜態方法,直接獲取到第一個匹配的值:
string mat = Regex.Match(input_txt,"(?<=\"UserID\":\").*?(?=\")", RegexOptions.IgnoreCase).Value;
2,查找匹配
按照正則來查看匹配的文本是正則表達式最常用的功能,
Regex re = new Regex("(?<=\"UserID\":\").*?(?=\")", RegexOptions.IgnoreCase); MatchCollection mc = re.Matches(text_input); foreach(Match mt in mc) { //mt.Value }
二,創建CLR工程
我使用的IDE版本是VS2017 Enterprise,要創建CLR工程,首先需要創建SQL Server 類型的 Project。
1,新建CLR函數
在已創建的SQL Server Project中添加新項目(Add -> New Item),選項SQL CLR C# User Defined Function,這里把文件命名為UserDefinedFunctions.cs。
2,編寫CLR代碼
完整的CLR標量函數示例代碼如下,Build 該文件,生成DLL文件,用該DLL文件創建程序集。
為了使用正則表達式,需要在文件中添加引用 : using System.Text.RegularExpressions;
using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; using System.Text; using System.Text.RegularExpressions; public partial class UserDefinedFunctions { [Microsoft.SqlServer.Server.SqlFunction] public static SqlString Match(string input, string pattern) { string str = Regex.Match(input, pattern, RegexOptions.IgnoreCase).Value; return new SqlString (str); } public static SqlBoolean IsMatch(string input, string pattern) { bool match = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase); return new SqlBoolean(match); } public static SqlString Matches(string input, string pattern) { MatchCollection mc = Regex.Matches(input, pattern, RegexOptions.IgnoreCase); StringBuilder strList = new StringBuilder(); int idx = 0; foreach(Match m in mc) { strList.Append(string.Format("\"idx{0}\":\"{1}\",", idx, m.Value)); idx = idx + 1; } return new SqlString(strList.ToString()); } public static SqlString SplitItem(string input, string separator, int idx) { string[] str = input.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries); return str.Length> idx ? str[idx] : ""; } public static string GetJsonItem(string input, string key) { string pattern = string.Format("(?<=\"{0}\":\").*?(?=\")", key); return Regex.Match(input, pattern, RegexOptions.IgnoreCase).Value; } }
三,在SQL Server中創建CLR函數
要在SQL Server數據庫中創建CLR函數,必須配置SQL Server的選項,然后使用DLL文件創建Assembly,並從Assembly創建SQL 函數。
1,配置SQL Server的選項
為了把CLR工程部署到SQL Server數據庫中,需要配置數據庫的高級選項,主要是禁用clr strict security 和啟用clr enabled選項。
exec sp_configure 'show advanced options', 1 go reconfigure; go exec sp_configure 'clr strict security', 0; go reconfigure; go exec sp_configure 'clr enabled', 1 go reconfigure go
2,創建程序集
引用CLR Project生成的DLL文件,用該DLL文件來創建SQL Server程序集:
CREATE ASSEMBLY [SQLServerDatabase] FROM 'E:\clr_project_path.dll' WITH PERMISSION_SET = SAFE GO
3,從程序集中創建SQL函數
把SQL Server Database Project中的創建的函數,逐個創建為SQL函數。
CREATE FUNCTION [dbo].[Match](@input [nvarchar](max), @pattern [nvarchar](max)) RETURNS [nvarchar](max) WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLServerDatabase].[UserDefinedFunctions].[Match] GO CREATE FUNCTION [dbo].[IsMatch](@input [nvarchar](max), @pattern [nvarchar](max)) RETURNS bit WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLServerDatabase].[UserDefinedFunctions].[IsMatch] GO CREATE FUNCTION [dbo].[Matches](@input [nvarchar](max), @pattern [nvarchar](max)) RETURNS [nvarchar](max) WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLServerDatabase].[UserDefinedFunctions].[Matches] GO CREATE FUNCTION [dbo].[SplitItem](@input [nvarchar](max), @separator [nvarchar](max), @idx int) RETURNS [nvarchar](max) WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLServerDatabase].[UserDefinedFunctions].[SplitItem] GO CREATE FUNCTION [dbo].[GetJsonItem](@input [nvarchar](max), @key [nvarchar](max)) RETURNS [nvarchar](max) WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLServerDatabase].[UserDefinedFunctions].[GetJsonItem] GO
在SQL函數創建之后,就可以像調用普通函數那樣來調用CLR函數。
update [dbo].[DimProductPath] set ProductPath_ProductFamily=dbo.SplitItem(ProductPath,'/',0) ,ProductPath_ProductName=dbo.SplitItem(ProductPath,'/',1) ,ProductPath_ProductVersion=dbo.SplitItem(ProductPath,'/',2) ,ProductPath_SupportTopic=dbo.SplitItem(ProductPath,'/',3) ,ProductPath_SupportSubtopic=dbo.SplitItem(ProductPath,'/',4)
參考文檔: