【问题标题】:SQL: case statement in order by clauseSQL:按子句排序的case语句
【发布时间】:2012-05-25 14:02:56
【问题描述】:

http://msdn.microsoft.com/en-us/library/ms181765.aspx

我从上面的链接看到下面的sql:

SELECT BusinessEntityID, SalariedFlag
FROM HumanResources.Employee
ORDER BY CASE SalariedFlag WHEN 1 THEN BusinessEntityID END DESC
    ,CASE WHEN SalariedFlag = 0 THEN BusinessEntityID END;
GO

这是我得到的一个结果:

BusinessEntityID,SalariedFlag

7,1

5,1

3,1

1,1

2,0

4,0

6,0

8,0

谁能解释为什么具有相同salariedFlag 的记录彼此相邻以及为什么salariedFlag=1 块高于salariedFlag=0 块?

【问题讨论】:

    标签: sql sql-server sql-order-by case


    【解决方案1】:

    sort子句等价于以下,可能稍微明显一点:

    ORDER BY CASE SalariedFlag WHEN 1 THEN BusinessEntityID ELSE null END DESC
            ,CASE WHEN SalariedFlag = 0 THEN BusinessEntityID ELSE null END;
    

    因此,当 SalariedFlag = 1 或 null 时,第一个排序字段是 BusinessEntityID。
    这会将 SalriedFlag = 0 的所有行组合在一起,因为它们都有一个空的第一个排序字段。
    SalariedFlag = 1 的行将按 BusinessEntityID 排序。看起来空值按降序排列在最后,所以所有 SalariedFlag != 1 排在最后。

    这是主要排序,对于次要排序,发生的情况大致相同:
    SalariedFlag = 0 的所有行将按 BusinessEntityID 排序。由于它们的主要排序字段均为空,因此它们最终将按 BusinessEntityID 排序。

    SalariedFlag != 0 的所有行都将与 null 二级排序组合在一起。如果这些行的 SalariedFlag = 1,那么它们已经按主排序进行了排序。

    如果 SalariedFlag 只能是 0 或 1,那么这种排序可以(稍微)简化为:

    ORDER BY CASE SalariedFlag WHEN 1 THEN BusinessEntityID END DESC
            , BusinessEntityID;
    

    【讨论】:

      【解决方案2】:

      通过在 SELECT 子句中包含 CASE WHEN 条件,您可以轻松地想象它为什么会以这种方式排序:

      SELECT BusinessEntityID, SalariedFlag,
      
      CASE SalariedFlag WHEN 1 THEN BusinessEntityID END AS A,
      CASE WHEN SalariedFlag = 0 THEN BusinessEntityID END AS B
      
      FROM Employee
      ORDER BY CASE SalariedFlag WHEN 1 THEN BusinessEntityID END DESC
          ,CASE WHEN SalariedFlag = 0 THEN BusinessEntityID END;
      

      输出:

      BUSINESSENTITYID  SALARIEDFLAG      A                 B
      7                 1                 7                 (null)
      5                 1                 5                 (null)
      3                 1                 3                 (null)
      1                 1                 1                 (null)
      2                 0                 (null)            2
      4                 0                 (null)            4
      6                 0                 (null)            6
      8                 0                 (null)            8
      

      SalariedFlag 0 保持在一起的原因是它们都落在 null 下(查看 A 列),如果 SalariedFlag 有另一个值,比如数字 2,那将是完全不同的事情,并且该查询将不再起作用,那些具有相同标志的人不一定彼此相邻。

      NULL 先排序,如果指定DESC,则最后排序。

      现场测试:http://www.sqlfiddle.com/#!3/1b849/13


      识别出该查询的 CASE WHEN 的 THEN 使用的是整数类型的 BusinessEntityID,您可以执行以下查询来达到相同的效果;由于它使用 SalariedFlag 作为分隔符,因此以下查询可能会更快,因为您没有在 ORDER BY 上使用条件。您可以切换 SalriedFlag 并对其进行排序:

      -- just to visualize things up
      SELECT BusinessEntityID, SalariedFlag,
      
          A = BusinessEntityID * SalariedFlag,
          B = BusinessEntityID * (SalariedFlag ^ 1) 
      
      FROM Employee
      ORDER BY A DESC, B 
      
      -- in actual you do this:
      
      SELECT BusinessEntityID, SalariedFlag
      
      FROM Employee
      ORDER BY BusinessEntityID * SalariedFlag DESC, BusinessEntityID * (SalariedFlag ^ 1) 
      

      鉴于此数据:

      CREATE TABLE [Employee]
          ([BusinessEntityID] int, [SalariedFlag] int);
      
      INSERT INTO [Employee]
          ([BusinessEntityID], [SalariedFlag])
      VALUES
          (10, 1),
          (5, 1),
          (9, 1),
          (1, 1),
          (2, 0),
          (7, 0),
          (6, 0),
          (8, 0);
      

      这是输出:

      BUSINESSENTITYID  SALARIEDFLAG      A                 B
      10                1                 10                0
      9                 1                 9                 0
      5                 1                 5                 0
      1                 1                 1                 0
      2                 0                 0                 2
      6                 0                 0                 6
      7                 0                 0                 7
      8                 0                 0                 8
      

      现场测试:http://www.sqlfiddle.com/#!3/e65ac/2

      【讨论】:

        【解决方案3】:

        当标志为1 时,您首先通过BusinessEntityID 订购,然后在标志为0 时通过BusinessEntityID 解决平局。这是因为当SalariedFlag 不是1 时,第一个CASE 表达式的计算结果为null,因此所有带有0 标志的记录都被移到带有1 标志的记录之后。

        【讨论】:

          【解决方案4】:

          尝试在您选择返回的值列表中包含 case 语句。它应该有助于澄清排序实际发生在哪些值上。

          【讨论】:

          • SalariedFlag 不是我所指的。尝试包括 CASE SalariedFlag WHEN 1 THEN BusinessEntityID END ,CASE WHEN SalariedFlag = 0 THEN BusinessEntityID END
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-21
          • 2018-07-04
          • 1970-01-01
          • 2020-03-26
          • 1970-01-01
          • 2015-09-26
          相关资源
          最近更新 更多