【问题标题】:SQL Server: ORDER BY parameters in IN statementSQL Server:IN 语句中的 ORDER BY 参数
【发布时间】:2016-08-03 18:28:34
【问题描述】:

我有一个如下的 SQL 语句:

SELECT A.ID, A.Name 
FROM Properties A 
WHERE A.ID IN (110, 105, 104, 106)

当我运行这条 SQL 语句时,输出会自动按照 ID 的IN 列表排序并返回

   104 West
   105 East
   106 North
   110 South

我想知道是否可以按照 IN 子句中列出的参数顺序进行排序。所以它会返回

 110 South
 105 East
 104 West
 106 North

【问题讨论】:

  • 不,不可能这样做。
  • 因为它们看起来是随机排列的,所以不——没有什么可订购的。 IN 不订购。
  • 所以你想不按特定顺序订购它......酷。
  • @JacobDeskin - 这不是我阅读问题的方式。您特别指出“我想知道是否可以按 IN 子句中列出的参数的顺序进行排序。
  • 如果值来自列表框,则 IN() 子句不一定按照用户单击项目的顺序,因此按 IN() 子句的顺序排序对您的用户毫无用处。

标签: sql sql-server tsql


【解决方案1】:

我认为 SQL Server 中最简单的方法是使用 JOINVALUES

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;

【讨论】:

  • 哈哈...没想到这个问题会引发这么多答案!!但都很有趣
  • 如果 OP 可以同时更改查询 应用程序(以传递顺序),这将起作用。如果 OP 无法更改应用程序以按顺序传递,UDF 解决方案会更好地工作。
【解决方案2】:

当然……

只需添加一个带有大小写的 Order 子句

 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

【讨论】:

  • 硬编码这些值不起作用 - 当下一个字符串被传入并且它是 112,47,108,96 时会发生什么?
【解决方案3】:

借助解析函数,它也返回序列

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

如果你需要,UDF

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

解析器会单独返回

Select * from [dbo].[udf-Str-Parse]('110,105,104,106',',')

Key_PS  Key_Value
1       110
2       105
3       104
4       106

【讨论】:

    【解决方案4】:

    你可能会做的是:

    1. 创建一个可以拆分字符串并保持原始顺序的 TVF。

    这个问题似乎已经写了这个函数:MS SQL: Select from a split string and retain the original order请记住,可能还有其他方法,不仅仅是这个问题中涵盖的那些,我只是作为一个例子来理解什么函数应该这样做

    如果你现在运行这个查询:

    SELECT *
    FROM dbo.Split('110,105,104,106', ',') AS T;
    

    结果会带回这个表。

    items rownum
    ------------
    110   1
    105   2
    104   3
    106   4
    

    然后,您可以简单地查询您的表,加入这个 TVF,并将您的 ID 作为参数传递:

    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;
    

    这应该保留参数的顺序。

    如果您需要更好的性能,我建议将 TVF 中的记录放入哈希表中,对其进行索引,然后与实际表连接。请参阅下面的查询:

    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;
    

    这应该更适用于较大的数据集,同样适用于小型数据集。

    【讨论】:

      【解决方案5】:

      这里是一个不依赖硬编码值或动态sql(消除硬编码值)的解决方案。

      我会用 OrderByValue 和 OrderBySort 构建一个表(可能是临时表或变量表)并从应用程序中插入。

      OrderByValue OrderBySort
      110            1
      105            2
      104            3
      106            4
      

      然后我会加入值并按排序排序。连接将与 In 子句相同。

      SELECT A.ID, A.Name 
         FROM Properties A 
         JOIN TempTable B On A.ID = B.OrderByValue
         Order By B.OrderBySort
      

      【讨论】:

        【解决方案6】:

        这个问题的另一个解决方案是为IN子句准备一个临时表

        declare @InTable table (ID int, SortOrder int not null identity(1,1));
        

        我们可以按照你想要的顺序用你的数据填充这个临时表

        insert into @InTable values (110), (105), (104), (106);
        

        最后我们需要修改你的问题以像这样使用这个临时表

        select A.ID, A.Name 
        from Properties A 
        inner join @InTable as Sort on A.ID = Sort.ID
        order by Sort.SortOrder
        

        在输出中你可以看到这个

        ID  Name
        110 South
        105 East
        104 West
        106 North
        

        在此解决方案中,您无需以特殊方式提供订单。你只需要按你想要的顺序插入值。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-12-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-12-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多