【问题标题】:Why and How do ORDER BY CASE Queries Work in SQL Server?为什么 ORDER BY CASE 查询在 SQL Server 中工作以及如何工作?
【发布时间】:2021-06-26 21:44:36
【问题描述】:

我们看下表:


| col1     | col2           |
| -------- | -------------- |
| 1        | NULL           |
| 23       | c              |
| 73       | NULL           |
| 43       | a              |
| 3        | d              |

假设你想这样排序:

| col1     | col2           |
| -------- | -------------- |
| 1        | NULL           |
| 73       | NULL           |
| 43       | a              |
| 23       | c              |
| 3        | d              |

使用以下代码,这几乎是微不足道的:

SELECT *
FROM dbo.table1
ORDER BY col2;

但是,按照以下非标准方式对其进行排序并不容易:

| col1     | col2           |
| -------- | -------------- |
| 43       | a              |
| 23       | c              |
| 3        | d              |
| 1        | NULL           |
| 73       | NULL           |

我用下面的代码做到了

SELECT *
FROM dbo.table1
ORDER BY CASE WHEN col2 IS NULL THEN 1 ELSE 0 END, col2;

您能向我解释一下 1) 为什么 和 2) 这个查询是如何工作的吗?令我烦恼的是,CASE 语句返回 1 或 0,这意味着将执行 ORDER BY 1, col2ORDER BY 0, col2。但是下面的代码给了我一个错误:

SELECT *
FROM dbo.table1
ORDER BY 0, col2;

然而,整体说法是有效的。为什么?

【问题讨论】:

  • 按数字排序(序数排序)是按该序数位置的列排序而不是值 0。但是列号从 1 开始,因此按 0 排序失败的原因.这是一种老式的、不推荐的订购方式。
  • 请注意,CASE 是一个表达式,因此 SQL 按该值排序。但是,对于常量表达式,会使用 SELECT 子句中列的序号。
  • 因为当您添加case 表达式(或任何计算)时,它不再被视为序数。
  • 它被视为自然数据类型,即 int。如果您考虑一下,ORDER BY 0 对每一行都有相同的值。 ORDER BY CASE WHEN col2 IS NULL THEN 1 ELSE 0 END 并不(不一定)对每一行都具有相同的值。有些行可以为 0,而其他行可以为 1,因此您按 int 排序(根据需要使用 desc 或 asc)。

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


【解决方案1】:

这是如何工作的?

ORDER BY (CASE WHEN col2 IS NULL THEN 1 ELSE 0 END),
         col2;

嗯,它完全按照代码指定的方式工作。 ORDER BY 的第一个键采用基于 col210 的值。 1 仅当值为NULL 时。因为 1 > 0,这些在非NULL 值之后排序。所以,所有非NULL 的值都排在第一位,然后是所有NULL 的值。

NULL 值如何排序?这就是第二个密钥的来源。它们按col2 排序。

【讨论】:

  • 我不知道 CASE 返回的 1 和 0 在像这样执行时不再引用列。考虑到这一点,您的答案是有道理的。
  • @MoritzWolff From Order By: "order_by_expression 指定对查询结果集进行排序的列或表达式。排序列可以指定为名称或列别名,或表示列在选择列表中的位置的非负整数。"请注意,only 非负整数将被解释为位置列引用。 case 和任何其他(非退化)表达式都不会被视为位置。另请参阅该页面上的最佳实践。
  • @HABO 是的,它不被视为一个位置,但它没有在 ORDER BY 的文档中指定它如何与 CASE 完全结合。你知道我在哪里可以找到这些信息吗?有点奇怪,我找到这方面信息的唯一地方是 Stackoverflow。
  • @MoritzWolff 。 . .它在order by 的文档中。但这可能有点难以理解,特别是如果英语不是您的母语。 order by 的位置参数仅在它们不是表达式的一部分时可用。
  • @MoritzWolff "[A] nonnegative integer" 表示 literal 值(又名integer constant,具有非负值。不,从文本中看不出来。想象一下如果任何时候您尝试对整数列(或表达式)进行排序,就会发生这种情况,每行通过动态选择排序列来决定它想要如何排序。如果该列结果是另一个整数并且...... . 那是行不通的。
【解决方案2】:

从这个示例数据开始:

--==== Sample Data
DECLARE @t TABLE (col1 INT, col2 VARCHAR(10))
INSERT @t(col1,col2) VALUES (1,NULL),(23,'c'),(73,NULL),(43,'a'),(3 ,'d');

现在请注意这三个查询完全相同做同样的事情。

--==== QUERY1: Note the derived query
SELECT t.col1, t.col2
FROM
(
  SELECT t.col1, t.col2, SortBy = CASE WHEN col2 IS NULL THEN 1 ELSE 0 END
  FROM   @t AS t
) AS t
ORDER BY t.SortBy;

--==== QUERY2: This does the same thing but with less code
SELECT   t.col1, t.col2, SortBy = CASE WHEN col2 IS NULL THEN 1 ELSE 0 END
FROM     @t AS t
ORDER BY SortBy;

--==== QUERY3: This is QUERY2 simplified
SELECT   t.col1, t.col2
FROM     @t AS t
ORDER BY CASE WHEN col2 IS NULL THEN 1 ELSE 0 END;

请注意,您可以像这样简化 CASE 语句:

--==== Simplified Case statemnt examples
SELECT   t.col1, t.col2
FROM     @t AS t
ORDER BY CASE col2 WHEN NULL THEN 1 ELSE 0 END;

SELECT   t.col1, t.col2
FROM     @t AS t
ORDER BY IIF(col2 IS NULL,1,0);

【讨论】:

    【解决方案3】:

    试试这个:

    DECLARE     @Table TABLE (col1 int, col2 char(1))
    INSERT INTO @Table
        VALUES  
                ( 1 , NULL)
            ,   ( 23, 'c'   )
            ,   ( 73, NULL)
            ,   ( 43, 'a'   )
            ,   ( 3 , 'd'   )
    ;
    
    SELECT *
    FROM @Table
    ORDER BY ISNULL(col2, CHAR(255))
    

    【讨论】:

      【解决方案4】:

      公用表表达式可以作为澄清和解决问题的一种方式提供很大帮助。如果您将 CASE 子句上移到 CTE 中,然后使用它进行排序,这将回答 为什么如何 它的工作原理。

      With Qry1 (
          SELECT      col1, 
                      col2, 
                      CASE WHEN col2 IS NULL THEN 1 ELSE 0 END As SortKey
          FROM        dbo.table1
      )
      SELECT      *
      FROM        Qry1
      ORDER BY    SortKey, col2;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-18
        • 1970-01-01
        • 2023-02-06
        • 1970-01-01
        相关资源
        最近更新 更多