Mimic Oracles INSTR Function
Starting at a user defined location in a string to find the nth occurance of a target string's starting location
EDIT: OK, I got Jay's set based method to work. And I mistook Jay for Jay White (Page47) but I was wrong (but I should be given a pass, because it's just like what Mr. 47 would have written). Now we have to ask, Jay who?
Not anymore, thanks Jay
Anyway Thanks Jay. Just as a note: This requires a numbers table. The concept of using this to eliminate recursion and cursors is sort of akin to turning a light on after stumbling around in the dark for so long (and even stumbling around in the light, since I couldn't employee this concept in my original shot at this). The reasons to not use set based processing is becoming smaller and smaller on a daily basis. Anyway, enjoy.
USE Northwind
GO
SET NOCOUNT ON
CREATE TABLE numbers(n int)
GO
DECLARE @x int
SET @x = 1
WHILE @x < 1001
BEGIN
INSERT INTO numbers(n) SELECT @x
SELECT @x = @x + 1
END
GO
CREATE FUNCTION udf_Instr
(@str1 varchar(8000), @str2 varchar(8000), @start int, @Occurs int)
RETURNS int
AS
BEGIN
DECLARE @instr int
SELECT TOP 1 @instr = instr
FROM (
SELECT d.*
, (SELECT COUNT(1)
FROM (SELECT DISTINCT CHARINDEX(@str1,SUBSTRING(@str2,@start,LEN(@str2)-@start+1),n) AS instr
FROM numbers
WHERE n <= LEN(@str2))AS d2
WHERE d2.instr <= d.instr) AS ct
FROM (SELECT DISTINCT CHARINDEX(@str1,SUBSTRING(@str2,@start,LEN(@str2)-@start+1),n) AS instr
FROM numbers
WHERE n <= LEN(@str2)) AS d
) AS d
GROUP BY instr,ct
HAVING ct <= @occurs
ORDER BY ct DESC
RETURN @instr
END
GO
SELECT dbo.udf_Instr('x','axbxcxdx',1,4)
GO
My Original shot:
CREATE FUNCTION udf_Instr
(@str1 varchar(8000), @str2 varchar(8000), @start int, @Occurs int)
RETURNS int
AS
BEGIN
DECLARE @Found int, @LastPosition int
SET @Found = 0
SET @LastPosition = @start - 1
WHILE (@Found < @Occurs)
BEGIN
IF (CHARINDEX(@str1, @str2, @LastPosition + 1) = 0)
BREAK
ELSE
BEGIN
SET @LastPosition = CHARINDEX(@str1, @str2, @LastPosition + 1)
SET @Found = @Found + 1
END
END
RETURN @LastPosition
END
GO
SELECT dbo.udf_Instr('x','axbxcxdx',1,4)
GO
DROP FUNCTION udf_Instr
GO
Legacy Comments
Xerxes
2005-02-02 |
re: Mimic Oracles INSTR Function Terrific looping technique! -Semper fi |
Brett
2005-02-02 |
Some Loops Can't be avoided You do what you can. Just try and avoid Cursors at all costs.... Unless you're using Oracle, then you have no choice for cetrain operations....besides, and I'll have to research this, I believe theu operate totally differently internally.. That would make a good article I guess. |
Jay
2005-02-02 |
re: Mimic Oracles INSTR Function Hi Brett, Here is a set-based method which perform the same functionality. I think... :) [code] select top 1 instr from ( select d.*, ( select count(1) from ( select distinct charindex(@str1,@str2,n) instr from numbers where n <= len(@str2) ) d2 where d2.instr <= d.instr ) as ct from ( select distinct charindex(@str1,@str2,n) instr from numbers where n <= len(@str2) ) d ) d group by instr,ct having ct <= @occurs order by ct desc [/code] |
Jay
2005-02-02 |
re: Mimic Oracles INSTR Function Well that did not format properly at all :( |
Brett
2005-02-03 |
No code tags Sorry, no code tags here...After I get a chance to underatnd it, I'll redit the post, turn it in to a function and format it...and supply a cut and pasteable code snipet. Thanks Jay But what happened to the @start parameter? |
Jay
2005-02-03 |
re: Mimic Oracles INSTR Function Oops, I guess I missed that one.. Just append it to where criterias making them. BETWEEN (@start and LEN(@str2) I did not test it all that much, just a few conditions. Give it a shake down and see if it works the same. |
Tara
2005-02-03 |
re: Mimic Oracles INSTR Function Me thinks Jay is ehorn from the forums. |
Jay (aka ehorn)
2005-02-03 |
re: Mimic Oracles INSTR Function Yea, its me. Sorry for the confusion. :) |
Brett
2005-02-04 |
Sorry? You take the time to give us code like that... No Sari's needed. Thanks again! EDIT: Damn can't make a nice hyperlink http://images.google.com/images?q=Sari&hl=en&lr=&sa=N&tab=ii&oi=imagest |
Adam Machanic
2005-02-04 |
re: Mimic Oracles INSTR Function I think the set-based solution looks nice, but you might instead want to use a table variable with an identity column, for efficiency's sake. In SS2005 the ROW_NUMBER function will do away with the need for that, luckily! |
Brett
2005-02-04 |
table variable? Do you mean to build a table variable everytime? Isn't that more overhead? And How would Rownumber help? |