SQL Server: ORDER BY parameters in IN statement

后端 未结 6 791
抹茶落季
抹茶落季 2020-12-21 19:38

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

相关标签:
6条回答
  • 2020-12-21 19:48

    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
    
    0 讨论(0)
  • 2020-12-21 19:59

    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;
    
    0 讨论(0)
  • 2020-12-21 20:02

    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.

    0 讨论(0)
  • 2020-12-21 20:08

    What you could potentially do is:

    1. Create a TVF that would split string and keep original order.

    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.

    0 讨论(0)
  • 2020-12-21 20:12

    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
    
    0 讨论(0)
  • 2020-12-21 20:13

    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
    
    0 讨论(0)
提交回复
热议问题