How to SORT in order as entered in SQL Server?

前端 未结 5 790
猫巷女王i
猫巷女王i 2020-12-04 00:44

I\'m using SQL Server and I\'m trying to find results but I would like to get the results in the same order as I had input the conditions.

My code:

S         


        
5条回答
  •  借酒劲吻你
    2020-12-04 01:21

    Okay, after some re-thinking I'll offer the ultimative XML based type-safe and sort-safe splitter:

    Declare @List varchar(max)='212345, 312345, 145687, 658975, 256987, 365874, 568974, 124578, 125689';
    DECLARE @delimiter VARCHAR(10)=', ';
    
    WITH Casted AS
    (
        SELECT (LEN(@List)-LEN(REPLACE(@List,@delimiter,'')))/LEN(REPLACE(@delimiter,' ','.')) + 1 AS ElementCount
               ,CAST('' + REPLACE((SELECT @List AS [*] FOR XML PATH('')),@delimiter,'')+'' AS XML) AS ListXml
    )
    ,Tally(Nmbr) As
    (
        SELECT TOP((SELECT ElementCount FROM Casted)) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values v1 CROSS JOIN master..spt_values v2
    )
    SELECT Tally.Nmbr AS Position
          ,(SELECT ListXml.value('(/x[sql:column("Tally.Nmbr")])[1]','int') FROM Casted) AS Item 
    FROM Tally;
    

    The trick is to create a list of running numbers with the fitting number of element (a number's table was even better) and to pick the elements according to their position.

    Hint: This is rather slow...

    UPDATE: even better:

    WITH Casted AS
    (
        SELECT (LEN(@List)-LEN(REPLACE(@List,@delimiter,'')))/LEN(REPLACE(@delimiter,' ','.')) + 1 AS ElementCount
               ,CAST('' + REPLACE((SELECT @List AS [*] FOR XML PATH('')),@delimiter,'')+'' AS XML)
               .query('
                       for $x in /x
                       return {$x/text()[1]}
                      ') AS ListXml
    )
    SELECT x.value('@p','int') AS Position
          ,x.value('text()[1]','int') AS Item 
    FROM Casted
    CROSS APPLY Casted.ListXml.nodes('/x') AS A(x);
    

    Elements are create as

    TheValue
    

    Regrettfully the XQuery function position() is not available to retrieve the value. But you can use the trick to count all elements before a given node. this is scaling badly, as this count must be performed over and over. The more elements the worse it goes...

    UPDATE2: With a known count of elements one might use this (much better performance)

    Use XQuery to iterate a literally given list:

    WITH Casted AS
    (
        SELECT (LEN(@List)-LEN(REPLACE(@List,@delimiter,'')))/LEN(REPLACE(@delimiter,' ','.')) + 1 AS ElementCount
               ,CAST('' + REPLACE((SELECT @List AS [*] FOR XML PATH('')),@delimiter,'')+'' AS XML)
               .query('
                       for $i in (1,2,3,4,5,6,7,8,9)
                       return {/x[$i]/text()[1]}
                      ') AS ListXml
    )
    SELECT x.value('@p','int') AS Position
          ,x.value('text()[1]','int') AS Item 
    FROM Casted
    CROSS APPLY Casted.ListXml.nodes('/x') AS A(x);
    

提交回复
热议问题