壹佰网|ERP100 - 企业信息化知识门户

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 1029|回复: 0

<ZT>如何用TSQL求子串在父串中出现的次数

[复制链接]
发表于 2008/4/9 13:32:01 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。如果您注册时有任何问题请联系客服QQ: 83569622  。

您需要 登录 才可以下载或查看,没有帐号?注册

x

    由于SQL Server本身没提供计算一个字符串在另一个字符串重复次数的函数,大家按照自己的思路使用自定义函数实现了该功能,并在网上传播。我阅读了同事从网上获取的该函数的一个版本后,便发现该函数存在一个明显的逻辑错误。为了进一步确认这个问题,我在Google上搜索相关关键字,发现该功能多数的实现思路一致,但大多数都存在这个共同的逻辑错误。可见从网络上获取的一些资源,可以作为参考,但要在实际需求中能够应用,是需要仔细检查的。   功能实现
  常见方法
  以下是网上一种较常见的函数实现:
SET ANSI_NULLS ON
GO
SET QUOTED_
IDENTIFIER ON
GO
--描述:利用循环得到一个字符串在另一个字符串中出现的次数
--DEMO:
-- SE
LECT dbo.f_getcharcount_false('df ththth','tht')
CREATE FUNCTION [dbo].[f_getcharcount_false](
@str varchar(
8000),
@chr varchar(8000)
) RET
URNS INT
AS
BEGIN
DECLARE @re INT,@i INT
SELECT @re=0,@i=charindex(@chr,@str)+1
WHILE @i>1
     SELECT @re=@re+1
         ,@str=substring(@str,@i,8000)
         ,@i=charindex(@chr,@str)+1

RETURN(@re)
END


  上面的函数设计思路是循环截断源字符串,通过计算截断的次数来获取子字符串出现的重复数。思路当然是可行的,但是在它截断的时候,起点是@i=charindex(@chr,@str)+1,这里就是错误的起因。以我给出的DEMO来讲,代码如下:
  SELECT dbo.f_getcharcount_false('df ththth','tht')
  结果为2,其实明显,正确的结果是1。因为上述函数的截断内容只有“t”,而后面的“ht”会被继续使用,导致“t”与后面的“ht”组合,结果计数多了一次。正确的截取位置应该从子串的位置结束处开始,就是从“tht”后面开始。
  既然思路正确,那么我们就修改上述代码中的错误,修改后的代码如下:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
--描述:利用循环得到一个字符串在另一个字符串中出现的次数
--DEMO:
--  SELECT dbo.f_getcharcount_true('df ththth','tht')
CRE
ATE FUNCTION [dbo].[f_getcharcount_true](
@str varchar(8000),
@chr varchar(8000)
) RETURNS INT
AS
BEGIN
DECLARE @re INT,@i INT
SELECT @re=0,@i=charindex(@chr,@str)+1
WHILE @i>1
     SELECT @re=@re+1
         ,@str=substring(@str,@i-1+len(@chr),8000)
         ,@i=charindex(@chr,@str)+1
RETURN(@re)
END


  当然,截断字符串很多人喜欢用stuff填充空字符,但网上流传的该版本,用stuff函数实现截断操作的,多数也是存在这个截断位置错误的。
  优化的方法
  上面讲的只是在网络上流传最广泛的方法,那么想要精炼代码,寻找更便捷和高效的方法也是可行。下面再介绍两种较便捷的实现方式。
  <方法一>
/*
描述:
利用字符串长度计算字符出现次数
DEMO:
SELECT dbo.f_get_char_repeat_count('df ththth','tht')
*/
CREATE FUNCTION [dbo].[f_get_char_repeat_count]
(@str VARCHAR(8000),
@substr VARCHAR(8000)
)
RETURNS INT
BEGIN
RETURN (LEN(@str)-LEN(REPLACE(@str,@substr,'')))/LEN(@substr)
END



<方法二>
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*
描述:利用长度差值求重复次数
DEMO:
SELECT fn_get_char_repeat_count_by_add_char('ahahaahde','ah')
*/
CREATE FUNCTION [dbo].[fn_get_char_repeat_count_by_add_char](
@str varchar(8000),--父串
@chr varchar(8000) --子串
) RETURNS INT
AS
BEGIN
RETURN(len(replace(@str,@chr,@chr+' '))-len(@str))
END


  上面的<方法一>是用空字符替换父字符串中出现的子串,用剩余字符串的长度与子字符串的长度求商;<方法二>是把为父字符串中出现子字符串的地方都增加个空格,用替换后的父字符串长度减去原父字符串的长度。
  总结
  面对日常的工作需求,针对具体的问题,关键在于思路的不同。网络上丰富的资源是可以借鉴的,但同时要注意辨别这些资源的可用性。网络资源的作用主要给我们借鉴,扩展我们的思路,不应该直接投入使用。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|Archiver|小黑屋|手机版|壹佰网 ERP100 ( 京ICP备19053597号-2 )

Copyright © 2005-2012 北京海之大网络技术有限责任公司 服务器托管由互联互通
手机:13911575376
网站技术点击发送消息给对方83569622   广告&合作 点击发送消息给对方27675401   点击发送消息给对方634043306   咨询及人才点击发送消息给对方138011526

GMT+8, 2025/11/30 20:32 , Processed in 0.011286 second(s), 14 queries , File On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表