導言
由於SQL Server本身沒提供計算一個字符串在另一個字符串重復次數的函數, 大家按照自己的思路使用自定義函數實現了該功能,並在網上傳播。我閱讀了同 事從網上獲取的該函數的一個版本後,便發現該函數存在一個明顯的邏輯錯誤。 為了進一步確認這個問題,我在Google上搜索相關關鍵字,發現該功能多數的實 現思路一致,但大多數都存在這個共同的邏輯錯誤。可見從網絡上獲取的一些資 源,可以作為參考,但要在實際需求中能夠應用,是需要仔細檢查的。
功能實現
常見方法
以下是網上一種較常見的函數實現:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
--描述:利用循環得到一個字符串在另一個字符串中出現的次數
--DEMO:
--SELECT dbo.f_getcharcount_false('df ththth','tht')
CREATE FUNCTION [dbo].[f_getcharcount_false](
@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,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')
CREATE 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函數實現截斷操作的,多數也是存在這個截斷位置錯誤的。