I have a SQL statement that is the following:
SELECT A.ID, A.Name
FROM Properties A
WHERE A.ID IN (110, 105, 104, 106)
When I run this SQ
With the help of a parsing function which returns the sequence as well
SELECT B.Key_PS
, A.ID
, A.Name
FROM Properties A
Join (Select * from [dbo].[udf-Str-Parse]('110,105,104,106',',')) B on A.ID=B.Key_Value
WHERE A.ID IN (110,105,104,106)
Order by Key_PS
The UDF if you need
CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimeter varchar(10))
--Usage: Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
-- Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
-- Select * from [dbo].[udf-Str-Parse]('id26,id46|id658,id967','|')
-- Select * from [dbo].[udf-Str-Parse]('hello world. It. is. . raining.today','.')
Returns @ReturnTable Table (Key_PS int IDENTITY(1,1), Key_Value varchar(max))
As
Begin
Declare @XML xml;Set @XML = Cast('<x>' + Replace(@String,@Delimeter,'</x><x>')+'</x>' as XML)
Insert Into @ReturnTable Select Key_Value = ltrim(rtrim(String.value('.', 'varchar(max)'))) FROM @XML.nodes('x') as T(String)
Return
End
The Parser alone would return
Select * from [dbo].[udf-Str-Parse]('110,105,104,106',',')
Key_PS Key_Value
1 110
2 105
3 104
4 106
I think the easiest way in SQL Server is to use a JOIN
with VALUES
:
SELECT p.ID, p.Name
FROM Properties p JOIN
(VALUES (110, 1), (105, 2), (104, 3), (106, 4)) ids(id, ordering)
ON p.id = a.id
ORDER BY ids.ordering;
Another solution for this problem is prepare a temporary table for IN clause like
declare @InTable table (ID int, SortOrder int not null identity(1,1));
We can fill this temp table with your data in order you want
insert into @InTable values (110), (105), (104), (106);
At last we need to modify your question to use this temp table like this
select A.ID, A.Name
from Properties A
inner join @InTable as Sort on A.ID = Sort.ID
order by Sort.SortOrder
On the output you can see this
ID Name
110 South
105 East
104 West
106 North
In this solution you don't need to provide order in special way. You just need to insert values in order you want.
What you could potentially do is:
This questions seems to have this function already written: MS SQL: Select from a split string and retain the original order (keep in mind that there might be other approaches, not only those, covered in this question, I just gave it as an example to understand what function should do)
So now if you'd run this query:
SELECT *
FROM dbo.Split('110,105,104,106', ',') AS T;
It would bring back this table as a result.
items rownum
------------
110 1
105 2
104 3
106 4
Following that, you could simply query your table, join with this TVF passing your IDs as a parameter:
SELECT P.ID, P.Name
FROM Properties AS P
INNER JOIN dbo.Split('110,105,104,106', ',') AS T
ON T.items = P.ID
ORDER BY T.rownum;
This should retain order of parameters.
If you need better performance, I'd advice to put records from TVF into hash table, index it and then join with actual table. See query below:
SELECT T.items AS ID, T.rownum AS SortOrder
INTO #Temporary
FROM dbo.Split('110,105,104,106', ',') AS T;
CREATE CLUSTERED INDEX idx_Temporary_ID
ON #Temporary(ID);
SELECT P.ID, P.Name
FROM Properties AS P
INNER JOIN #Temporary AS T
ON T.ID = P.ID
ORDER BY T.SortOrder;
This should work better on larger data sets and equally well on small ones.
Here is a solution that does not rely on hard codes values or dynamic sql (to eliminate hard coding values).
I would build a table (maybe temp or variable) with OrderByValue and OrderBySort and insert from the application.
OrderByValue OrderBySort
110 1
105 2
104 3
106 4
Then I would join on the value and sort by the sort. The join will be the same as the In clause.
SELECT A.ID, A.Name
FROM Properties A
JOIN TempTable B On A.ID = B.OrderByValue
Order By B.OrderBySort
Sure...
just add an Order clause with a case in it
SELECT A.ID, A.Name
FROM Properties A
WHERE A.ID IN (110,105,104,106)
Order By case A.ID
when 110 then 0
when 105 then 1
when 104 then 2
when 106 then 3 end