I have absolutely no idea why anyone wants to do this, but I keep answering the same question in forums: “How do I count the occurrences of a substring [note: usually comma] within a string?”
In an effort to thwart carpal tunnel syndrome, I have created the Ultimate Substring Occurrence Counting UDF.
… And here it is:
CREATE FUNCTION dbo.GetSubstringCount ( @InputString TEXT, @SubString VARCHAR(200), @NoisePattern VARCHAR(20) ) RETURNS INT WITH SCHEMABINDING AS BEGIN RETURN ( SELECT COUNT(*) FROM dbo.Numbers N WHERE SUBSTRING(@InputString, N.Number, LEN(@SubString)) = @SubString AND PATINDEX(@NoisePattern, SUBSTRING(@InputString, N.Number + LEN(@SubString), 1)) = 0 AND 0 = CASE WHEN @NoisePattern = '' THEN 0 ELSE PATINDEX(@NoisePattern, SUBSTRING(@InputString, N.Number - 1, 1)) END ) END
First note: You need (regular readers, you guessed it) a numbers table.
Okay, so what’s it do? Simply put, it returns the number of times @SubString appears within @InputString. But wait! — Act now and you will receive an additional bonus feature at no extra cost! Can you feel the love?
The @NoisePattern parameter allows the user to put the UDF into “exact match” mode.
For instance, let’s say you have a big string containing some text about automobile manufacturers, and for some reason (again, I have no clue why people need this functionality — fill me in if you do!) you want to count the number of occurrences of the word “auto”, but not the number of occurrences of other forms of the word, e.g. “automobile” or …. some word that ends in “auto” (if such a word exists).
By specifying a pattern for @NoisePattern of characters that shouldn’t be adjacent to your word, you’re telling the UDF that any other characters are safe. Leaving the parameter empty means that all occurrences of the substring will be counted. Examples:
SELECT dbo.GetSubstringCount('We like the autos, the autos that go boom.', 'auto', '') -- Returns 2 SELECT dbo.GetSubstringCount('Autos are fun. I like to drive my auto.', 'auto', '') -- Also returns 2 SELECT dbo.GetSubstringCount('Autos are fun. I like to drive my auto.', 'auto', '%[a-z]%') -- Only returns 1 -- The exact match must not have adjacent alphabetic characters