发布时间:2025-11-05 13:13:54 来源:技术快报 作者:域名

SQL Serve提供了简单的数式字符模糊匹配功能,比如:like,据库 patindex,不过对于某些字符处理场景还显得并不足够,正则字符日常碰到的表达几个问题有:
同一个字符/字符串,出现了多少次同一个字符,处理第N次出现的问题位置多个相同字符连续,合并为一个字符是数式否为有效IP/身份证号/手机号等一. 同一个字符/字符串,出现了多少次同一个字符,据库将其替换为空串,正则字符即可计算
复制declare @text varchar(1000)declare @str varchar(10)set @text = ABCBDBEset @str = Bselect len(@text) - len(replace(@text,表达@str,))1.2.3.4.5.同一个字符串,仍然是处理替换,因为是问题多个字符,方法1替换后需要做一次除法;方法2替换时增加一个字符,数式则不需要
—方法1
复制declare @text varchar(1000)declare @str varchar(10)set @text = ABBBCBBBDBBBEset @str = BBBselect (len(@text) - len(replace(@text,据库@str,)))/len(@str)1.2.3.4.5.—方法2
复制declare @text varchar(1000)declare @str varchar(10)set @text = ABBBCBBBDBBBEset @str = BBBselect len(replace(@text,@str,@str+_)) - len(@text)1.2.3.4.5. 二. 同一个字符/字符串,第N次出现的正则字符位置SQL SERVER定位字符位置的函数为CHARINDEX:
CHARINDEX ( expressionToFind , expressionToSearch [ , start_location ] )CHARINDEX ( expressionToFind , expressionToSearch [ , start_location ] )
可以从指定位置起开始检索,但是不能取第N次出现的位置,需要自己写SQL来补充,有以下几种思路:
1、 自定义函数, 循环中每次为charindex加一个计数,直到为N
复制if object_id(NthChar,FN) is not null dropfunction Nthchar
GO
createfunction NthChar
(@source_string as nvarchar(4000),@sub_string as nvarchar(1024),@nth as int)returns intasbegin declare @postion int declare @count int set @postion = CHARINDEX(@sub_string, @source_string) set @count = 0 while @postion > 0 begin set @count = @count + 1 if @count =@nth
beginbreak
end
set @postion = CHARINDEX(@sub_string, @source_string, @postion + 1)End
return @postion
end
GO
--select dbo.NthChar(abcabc,abc,2)--41.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.2、 通过CTE,对待处理的整个表字段操作, 递归中每次为charindex加一个计数,直到为N
复制if object_id(tempdb..#T) is not null drop table#T
create table#T
(source_string nvarchar(4000))insert into #T values (N我们我们)insert into #T values (N我我哦我)declare @sub_string nvarchar(1024)declare @nth intset @sub_string = N我们set @nth = 2;with T(source_string, starts, pos, nth)as ( select source_string, 1, charindex(@sub_string, source_string), 1 from#t
unionall
select source_string, pos + 1, charindex(@sub_string, source_string, pos + 1), nth+1 fromT
where pos > 0)select source_string, pos,nth
fromT
where pos <> 0 and nth =@nth
order by source_string,starts
--source_string pos nth--我们我们 3 21.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.3、IT技术网 借助数字表 (tally table),到不同起点位置去做charindex,需要先自己构造个数字表
复制
--numbers/tally tableIF EXISTS (select * from dbo.sysobjects where id = object_id(N[dbo].[Numbers]) and OBJECTPROPERTY(id, NIsUserTable) = 1) DROP TABLE dbo.Numbers--===== Create and populate the Tally table on the fly SELECT TOP 1000000 IDENTITY(int,1,1) ASnumber
INTO dbo.Numbers FROM master.dbo.syscolumns sc1, master.dbo.syscolumnssc2
--===== Add a Primary Key to maximize performance ALTER TABLE dbo.Numbers ADD CONSTRAINT PK_numbers_number PRIMARY KEY CLUSTERED (number)--===== Allow the general public to use it GRANT SELECT ON dbo.NumbersTO PUBLIC
--以上数字表创建一次即可,不需要每次都重复创建DECLARE @source_string nvarchar(4000), @sub_string nvarchar(1024), @nth intSET @source_string = abcabcvvvvabcSET @sub_string = abcSET @nth = 2;WITH T
AS(SELECT ROW_NUMBER() OVER(ORDER BY number) AS nth, number AS [Position In String] FROM dbo.Numbersn
WHERE n.number <= LEN(@source_string) AND CHARINDEX(@sub_string, @source_string, n.number)-number = 0 ----OR --AND SUBSTRING(@source_string,number,LEN(@sub_string)) = @sub_string)SELECT * FROM T WHERE nth = @nth1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.4、 通过CROSS APPLY结合charindex,适用于N值较小的时候,因为CROSS APPLY的次数要随着N的变大而增加,语句也要做相应的修改
复制declare @T table(source_string nvarchar(4000))insert into @T values(abcabc),(abcabcvvvvabc)declare @sub_string nvarchar(1024)set @sub_string = abcselect source_string, p1.pos as no1, p2.pos as no2, p3.pos asno3
from@T
cross apply (select (charindex(@sub_string, source_string))) as P1(Pos)cross apply (select (charindex(@sub_string, source_string, P1.Pos+1))) as P2(Pos)cross apply (select (charindex(@sub_string, source_string, P2.Pos+1))) as P3(Pos)1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.5. 在SSIS里有内置的函数,但T-SQL中并没有
复制--FINDSTRING in SQL Server 2005 SSISFINDSTRING([yourColumn], "|", 2),--TOKEN in SQL Server 2012 SSISTOKEN(Col1,"|",3)1.2.3.4.注:不难发现,这些方法和字符串拆分的逻辑是类似的,只不过一个是定位,一个是截取,如果要获取第N个字符左右的一个/多个字符,有了N的位置,再结合substring去截取即可;
三. 多个相同字符连续,合并为一个字符最常见的就是把多个连续的空格合并为一个空格,解决思路有两个:
1、 比较容易想到的服务器托管就是用多个replace
但是究竟需要replace多少次并不确定,所以还得循环多次才行
—把两个连续空格替换成一个空格,然后循环,直到charindex检查不到两个连续空格
复制declare @str varchar(100)set @str=abc abc kljlk kljklwhile(charindex(,@str)>0)begin select @str=replace(@str,,)end
select @str1.2.3.4.5.6.7.2、 按照空格把字符串拆开
对每一段拆分开的字符串trim或者replace后,再用一个空格连接,有点繁琐,没写代码示例,如何拆分字符串可参考:“第N次出现的位置”;
四. 是否为有效IP/身份证号/手机号等类似IP/身份证号/手机号等这些字符串,往往都有自身特定的规律,通过substring去逐位或逐段判断是可以的,但SQL语句的方式往往性能不佳,建议尝试正则函数,见下。
五. 正则表达式函数1、 Oracle
从10g开始,可以在查询中使用正则表达式,它通过一些支持正则表达式的函数来实现:
Oracle 10 g
REGEXP_LIKE
REGEXP_REPLACE
REGEXP_INSTR
REGEXP_SUBSTR
Oracle 11g (新增)
REGEXP_COUNT
Oracle用REGEXP函数处理上面几个问题:
(1) 同一个字符/字符串,出现了多少次
复制select length(regexp_replace(123-345-566, [^-], )) from dual;select REGEXP_COUNT(123-345-566, -) from dual; --Oracle 11g1.2.(2) 同一个字符/字符串,第N次出现的位置
不需要正则,ORACLE的instr可以直接查找位置:
复制instr(source_string,sub_string [,n][,m])1.n表示从第n个字符开始搜索,b2b信息网缺省值为1,m表示第m次出现,缺省值为1。
复制select instr(abcdefghijkabc,abc, 1, 2) position from dual;1.(3) 多个相同字符连续,合并为一个字符
复制select regexp_replace(trim(agc f f ),\s+,) from dual;1.(4) 是否为有效IP/身份证号/手机号等
—是否为有效IP
复制WITH IP
AS(SELECT 10.20.30.40 ip_address FROM dual UNIONALL
SELECT a.b.c.d ip_address FROM dual UNIONALL
SELECT 256.123.0.254 ip_address FROM dual UNIONALL
SELECT 255.255.255.255 ip_address FROMdual
)SELECT *FROMIP
WHERE REGEXP_LIKE(ip_address, ^(([0-9]{1}|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1}|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$);1.2.3.4.5.6.7.8.9.10.是否为有效身份证/手机号,暂未举例。
2、SQL Server
目前最新版本为SQL Server 2017,还没有对REGEXP函数的支持,需要通用CLR来扩展,如下为CLR实现REG_REPLACE:
1、 开启 CLR
复制EXEC sp_configure show advanced options , 1GO
RECONFIGURE
GO
EXEC sp_configure clr enabled , 1GO
RECONFIGURE
GO
EXEC sp_configure show advanced options , 0;GO1.2.3.4.5.6.7.8.9.10.2、 创建 Assembly
3、 创建 CLR 函数
复制CREATE FUNCTION [dbo].[regex_replace](@input [nvarchar](4000), @pattern [nvarchar](4000), @replacement [nvarchar](4000))RETURNS [nvarchar](4000) WITH EXECUTE AS CALLER, RETURNS NULL ON NULLINPUT
ASEXTERNAL NAME [RegexUtility].[RegexUtility].[RegexReplaceDefault]GO1.2.3.4.5.4、 使用regex_replace替换多个空格为一个空格
复制select dbo.regex_replace(agc f f ,\s+,);1.注:通过CLR实现更多REGEXP函数,如果有高级语言开发能力,可以自行开发;或者直接使用一些开源贡献也行。
1、 非正则SQL语句的思路,对不同数据库往往都适用;
2、 正则表达式中的规则(pattern) 在不同开发语言里,有很多语法是相通的,通常是遵守perl或者linux shell中的sed等工具的规则;
3、 从性能上来看,通用SQL判断 > REGEXP函数 > 自定义SQL函数。
总结:以上所述是小编给大家介绍的SqlServer类似正则表达式的字符处理问题,希望对大家有所帮助。