Situation:
I often have (no comments on database, it is history :)) columns where values are separated.
So let’s say we have a column params which contains for example 1,2,3,4,5.
If I need the values table based I split them with a dbo.fn_Split() function (several version can be found on the net – but out of scope here). So I get my virtual table.
Today I ran into a situation where I have a column where I have this content 110&mode=tree.
As I needed the ID only I said to myself… like usual, split and get the first value only:
SELECT TOP 1 [value] FROM dbo._fnSplit('110&mode=tree','&')
As I needed the value as int I added a CAST() around it.
CAST((SELECT TOP 1 [value] FROM dbo._fnSplit('110&mode=tree','&')) AS int)
Now after execution I got:
mode=tree cannot be converted to a type int
Huch? I get only the first value which is an Id (I double checked the results) but it still try to convert the 2nd value as well. So it seems that SQL Server handles it differently in execution.
Question:
So is it generally possible to control how the execution plans handle this behaviour?
Sidenote:
I solved it for now doing this:
[...] WHERE id = CAST((CASE WHEN k.param LIKE '%&%' THEN LEFT(k.swindowparam,PATINDEX('%&%',k.param)-1) ELSE k.swindowparam END) AS int))
Check if string contains & and if so so a LEFT with length found out by PATINDEX.
EDIT:
Here is the split function:
CREATE FUNCTION dbo.fn_Split(@text nvarchar(4000), @delimiter char(1) = ',')
RETURNS @Strings TABLE
(
position int IDENTITY PRIMARY KEY,
value nvarchar(4000)
)
AS
BEGIN
DECLARE @index int
SET @index = -1
SET @text = RTRIM(LTRIM(@text))
WHILE (LEN(@text) > 0)
BEGIN
SET @index = CHARINDEX(@delimiter , @text)
IF (@index = 0) AND (LEN(@text) > 0)
BEGIN
INSERT INTO @Strings VALUES (@text)
BREAK
END
IF (@index > 1)
BEGIN
INSERT INTO @Strings VALUES (LEFT(@text, @index - 1))
SET @text = RIGHT(@text, (LEN(@text) - @index))
END
ELSE
SET @text = RIGHT(@text, (LEN(@text) - @index))
END
RETURN
END
It sounds like your split function is returning the data in an unspecified order. To solve the problem I would change that function so it returns the results in the expect order every time.
Depending on how the function is implemented you may be able to correct this behavior by adding an ORDER BY statement. SQL Server doesn’t guarantee that a set will be returned in any specific order by default.