1

I'm converting a stored procedure from MySql to SQL Server. The procedure has one input parameter nvarchar/varchar which is a comma-separated string, e.g.

'1,2,5,456,454,343,3464'

I need to write a query that will retrieve the relevant rows, in MySql I'm using FIND_IN_SET and I wonder what the equivalent is in SQL Server.

I also need to order the ids as in the string.

The original query is:

 SELECT * 
 FROM table_name t
 WHERE FIND_IN_SET(id,p_ids)
 ORDER BY FIND_IN_SET(id,p_ids);
2
  • You need to either parse your string into the values, use dynamic sql, or change your list into a table parameter. I would avoid the dynamic sql for this unless you absolutely must, a table parameter is probably the best choice performance wise followed by splitting the string. Commented Dec 12, 2014 at 21:10
  • Tx, I will read about table parameter Commented Dec 12, 2014 at 21:15

4 Answers 4

4

The equivalent is like for the where and then charindex() for the order by:

select *
from table_name t
where ','+p_ids+',' like '%,'+cast(id as varchar(255))+',%'
order by charindex(',' + cast(id as varchar(255)) + ',', ',' + p_ids + ',');

Well, you could use charindex() for both, but the like will work in most databases.

Note that I've added delimiters to the beginning and end of the string, so 464 will not accidentally match 3464.

Sign up to request clarification or add additional context in comments.

Comments

1

You would need to write a FIND_IN_SET function as it does not exist. The closet mechanism I can think of to convert a delimited string into a joinable object would be a to create a table-valued function and use the result in a standard in statement. It would need to be similar to:

DECLARE @MyParam NVARCHAR(3000)

SET @MyParam='1,2,5,456,454,343,3464'

SELECT 
    * 
FROM 
    MyTable 
WHERE 
    MyTableID IN (SELECT ID FROM dbo.MySplitDelimitedString(@MyParam,','))

And you would need to create a MySplitDelimitedString type table-valued function that would split a string and return a TABLE (ID INT) object.

Comments

0

A set based solution that splits the id's into ints and join with the base table which will make use of index on the base table id. I assumed the id would be an int, otherwise just remove the cast.

declare @ids nvarchar(100) = N'1,2,5,456,454,343,3464';

with nums as ( -- Generate numbers
    select top (len(@ids)) row_number() over (order by (select 0)) n
    from sys.messages
)
, pos1 as ( -- Get comma positions
    select c.ci
    from nums n
        cross apply (select charindex(',', @ids, n.n) as ci) c
    group by c.ci
)
, pos2 as ( -- Distinct posistions plus start and end
    select ci
    from pos1
    union select 0
    union select len(@ids) + 1
)
, pos3 as ( -- add row number for join
    select ci, row_number() over (order by ci) as r
    from pos2
)
, ids as ( -- id's and row id for ordering
    select cast(substring(@ids, p1.ci + 1, p2.ci - p1.ci - 1) as int) id, row_number() over (order by p1.ci) r
    from pos3 p1
        inner join pos3 p2 on p2.r = p1.r + 1
)
select *
from ids i
    inner join table_name t on t.id = i.id
order by i.r;

Comments

0

You can also try this by using regex to get the input values from comma separated string :

select * from table_name where id in ( select regexp_substr(p_ids,'[^,]+', 1, level) from dual connect by regexp_substr(p_ids, '[^,]+', 1, level) is not null );

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.