SQL Server 没有内置的 Regex 函数,但它们可以通过 CLR 获得。好消息是 SQL Server 中不需要 Regex。我以前用 RegEx 做的所有事情现在都用NGrams8k 处理。这很容易并且性能更好。我已经使用 NGrams8K 构建了一些对这个问题和许多其他问题有帮助的函数。首先我们有PatReplace8K,第二个是Translate8K(更新了下面的代码。)第三个选项是PatExtract8K(点击代码链接)。
每个执行文本转换的示例。对于每个函数,我只是从“SomeString”中删除 Alpha 字符和 0-5 中的数字:
--==== Sample Data
DECLARE @table TABLE (SomeId INT IDENTITY, SomeString VARCHAR(40));
INSERT @table(SomeString) VALUES(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID());
--==== Using Patreplace8k
SELECT t.SomeString, f.NewString
FROM @table AS t
CROSS APPLY samd.patReplace8K(t.SomeString,'[0-5A-F-]','') AS f
--==== Using Translate8K
SELECT t.SomeString, f.NewString
FROM @table AS t
CROSS APPLY samd.Translate8K(t.SomeString,'[012345ABCDEF-]','') AS f
--==== samd.patExtract8K
SELECT t.SomeString,
NewString = STRING_AGG(f.item,'') WITHIN GROUP (ORDER BY f.ItemNumber)
FROM @table AS t
CROSS APPLY samd.patExtract8K(t.SomeString,'[0-5A-F-]') AS f
GROUP BY t.SomeString;
每次返回:
SomeString NewString
---------------------------------------- -----------------
0818BEF3-E0B3-4B3B-AA97-649E43EB16AF 8897696
3077EE8B-9E92-4337-9E2F-97DABE2E4623 7789979976
6BCD8194-F993-42DB-AF4A-D8289F8F8DA3 6899988988
C1F152DF-8B6F-4C14-AF6F-AC8869099FDB 866886999
F877D888-245E-4CEB-84B7-1CFF6E03B974 87788887697
要执行字符串聚合,您可以使用 XML PATH() 或 STRING_AGG。下面是一个同时使用技术和 PatReplace8k 的示例:
SELECT NewString = STUFF((
SELECT '//'+NewString
FROM @table AS t
CROSS APPLY samd.patReplace8K(t.SomeString,'[0-5A-F-]','') AS f
ORDER BY f.NewString
FOR XML PATH('')),1,2,'');
SELECT STRING_AGG(f.NewString,'//') WITHIN GROUP (ORDER BY f.NewString)
FROM @table AS t
CROSS APPLY samd.patReplace8K(t.SomeString,'[0-5A-F-]','') AS f;
在每种情况下,我都会得到我想要的:
NewString
----------------------------------------------------
6967899797//777689886//868796//8887789//88989
翻译功能:
CREATE OR ALTER FUNCTION samd.Translate8K
(
@string VARCHAR(8000), -- Input
@pattern VARCHAR(100), -- characters to replace
@key VARCHAR(100) -- replacement characters
)
/*
Purpose:
Standard Translate function - the fastest UDF version in the game. Enjoy.
For more about TRANSLATE see: https://www.w3schools.com/sql/func_sqlserver_translate.asp
Requires:
NGrams8K; get you some here:
https://www.sqlservercentral.com/articles/nasty-fast-n-grams-part-1-character-level-unigrams
Designed By Alan Burstein; May, 2021
*/
RETURNS TABLE WITH SCHEMABINDING AS RETURN
SELECT NewString = ISNULL(REPLACE(tx.NewString,CHAR(0),''),@string)
FROM
(
SELECT STRING_AGG(CAST(t.tKey+ng.Token AS CHAR(1)),'')
WITHIN GROUP (ORDER BY ng.Position)
FROM samd.ngrams8k(@string,1) AS ng
CROSS APPLY (VALUES(@key+REPLICATE(CHAR(0),100))) AS tx(NewKey)
CROSS APPLY (VALUES(CHARINDEX(ng.Token,@pattern))) AS pos(N)
CROSS APPLY (VALUES(SUBSTRING(tx.NewKey,pos.N,1))) AS t(tKey)
) AS tx(NewString);
Patreplace8k:
CREATE OR ALTER FUNCTION [samd].[patReplace8K]
(
@string VARCHAR(8000),
@pattern VARCHAR(50),
@replace VARCHAR(20)
)
/*****************************************************************************************
[Purpose]:
Given a string (@string), a pattern (@pattern), and a replacement character (@replace)
patReplace8K will replace any character in @string that matches the @Pattern parameter
with the character, @replace.
[Author]:
Alan Burstein
[Compatibility]:
SQL Server 2008+
[Syntax]:
--===== Basic Syntax Example
SELECT pr.NewString
FROM samd.patReplace8K(@String,@Pattern,@Replace) AS pr;
[Developer Notes]:
1. @Pattern IS case sensitive but can be easily modified to make it case insensitive
2. There is no need to include the "%" before and/or after your pattern since since we
are evaluating each character individually
3. Certain special characters, such as "$" and "%" need to be escaped with a "/"
like so: [/$/%]
4. Functions that use samd.ngrams8k will see huge performance gains when the optimizer
generates a parallel execution plan. One way to get a parallel query plan (if the
optimizer does not choose one) is to use make_parallel by Adam Machanic found here:
sqlblog.com/blogs/adam_machanic/archive/2013/07/11/next-level-parallel-plan-porcing.aspx
As is the case with functions which leverage samd.ngrams or samd.ngrams8k,
samd.patReplace8K is almost always dramatically faster with a parallel execution
plan. On my PC (8 logical CPU, 64GB RAM, SQL 2019) samd.patReplace8K is about 4X
faster when executed using all 8 of my logical CPUs.
5. samd.patReplace8K is deterministic. For more about deterministic functions see:
https://msdn.microsoft.com/en-us/library/ms178091.aspx
[Examples]:
--===== 1. Replace numeric characters with a "*"
SELECT pr.NewString
FROM samd.patReplace8K('My phone number is 555-2211','[0-9]','*') AS pr;
--==== 2. Using againsts a table
DECLARE @table TABLE(OldString varchar(60));
INSERT @table VALUES ('Call me at 555-222-6666'), ('phone number: (312)555-2323'),
('He can be reached at 444.665.4466 on Monday.');
SELECT t.OldString, pr.NewString
FROM @table AS t
CROSS APPLY samd.patReplace8K(t.oldstring,'[0-9]','*') AS pr;
[Revision History]:
-----------------------------------------------------------------------------------------
Rev 00 - 20141027 Initial Development - Alan Burstein
Rev 01 - 20141029 - Redesigned based on the dbo.STRIP_NUM_EE by Eirikur Eiriksson
(see: http://www.sqlservercentral.com/Forums/Topic1585850-391-2.aspx)
- change how the cte tally table is created
- put the include/exclude logic in a CASE statement instead of a WHERE clause
- Added Latin1_General_BIN Colation
- Add code to use the pattern as a parameter. - Alan Burstein
Rev 02 - 20141106 - Added final performance enhancement (more cudos to Eirikur Eiriksson)
- Put 0 = PATINDEX filter logic into the WHERE clause
Rev 03 - 20150516 - Updated to deal with special XML characters - Alan Burstein
Rev 04 - 20170320 - changed @replace from char(1) to varchar(1) for whitespace handling
- Alan Burstein
Rev 05 - 20200515 - Complete rewrite using samd.NGrams
- changed PATINDEX(...)=0 to: PATINDEX()&0x01=0;
- Changed CASE statement to IIF; Dropped collation - Alan Burstein
*****************************************************************************************/
RETURNS TABLE WITH SCHEMABINDING AS RETURN
SELECT NewString = STRING_AGG(IIF(PATINDEX(@pattern,col.Token)&0x01=0,col.Token,
@replace),'') WITHIN GROUP (ORDER BY ng.position)
FROM samd.NGrams8K(@string,1) AS ng
CROSS APPLY (VALUES(ng.token)) AS col(Token);