【问题标题】:Incorrect syntax for Order by clause with multiple columns具有多列的 Order by 子句的语法不正确
【发布时间】:2019-06-04 02:58:20
【问题描述】:

如何在case语句中编写多列的order by子句?

 ORDER BY 
 CASE 
 WHEN @T='ABC' Then Val,Seq
 ELSE Seq END

也试过了

 ORDER BY 
 CASE 
 WHEN @T='ABC' Then Convert(int,Val) 
 WHEN @T='ABC' Then Convert(nvarchar,Seq)
 ELSE Seq END

 ORDER BY 
 CASE 
 WHEN @T='ABC' Then Val,Seq
 ELSE Seq END

下面给出的代码也会抛出错误:

“执行存储过程时,此语句给出错误:“将 nvarchar 值 'EX-02-60' 转换为数据类型 int 时转换失败”。”

【问题讨论】:

  • 这种尝试是倒退的。将 case expression 放在 ORDER BY 中。
  • 当我建议进行此更改时,我已经在您的 other question 的评论中确切地告诉了您应该写什么。
  • OP 我更新了我的答案以明确和了解更多详细信息,并包含现场演示。
  • @Damien_The_Unbeliever 是的,你做到了。但是我遇到了语法问题,并且发生了另一个错误。因此,我将此帖子添加为单独的链。虽然这个问题仍然悬而未决,但代码已经过优化,但性能仍然保持不变,我在那个问题中也提到过。

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


【解决方案1】:

让我们创建一个包含您的列的表

CREATE TABLE T(
  Val VARCHAR(45),
  Seq INT,
  Sequence INT
);

INSERT INTO T VALUES
('A', 1, 2),
('C', 2, 1),
('B', 3, 3);

现在,让我们看看你的代码,然后带上条件:

这是您的代码:

 ORDER BY 
 CASE 
 WHEN @T='ABC' Then Val,Seq
 ELSE Sequence END
  • 如果是@T = 'ABC,则按ValSeq 订购不要Sequence 订购。
  • 如果@T <> 'ABC'Sequence 一起订购。

如果您运行此查询:

--You was trying--

DECLARE @T VARCHAR(3) = 'ABC'; --wil works only when @T <> ABC

SELECT *
FROM T
ORDER BY CASE WHEN @T='ABC' THEN Seq END, --Take INT
         CASE WHEN @T='ABC' THEN Val --Take Varchar
              ELSE Sequence -- Take INT
         END;

如果@T = 'ABC'会抛出如下错误

消息 245 级别 16 状态 1 第 5 行

将 varchar 值“A”转换为数据类型 int 时转换失败。

和你得到的一样

将 nvarchar 值“EX-02-60”转换为数据类型 int 时转换失败。

现在,根据您提供的条件,这是您想要的:

--Fixes--

DECLARE @T VARCHAR(3) = '1'; --Try to change it to ABC too

SELECT *
FROM T
ORDER BY CASE WHEN @T='ABC' THEN Val END, --Take varchar
         CASE WHEN @T='ABC' THEN Seq -- Take INT
              ELSE Sequence -- Take INT
         END;
/*
 IF @T = ABC
 ORDER BY Val, Seq; NOT Sequence
 
 IF @T <> ABC
 ORDER BY ONLY Sequence
*/

这是一个Live demo

【讨论】:

  • 早期的代码对我来说很好用。我还没有测试你提供的最新版本。
  • @SRawat 较早的代码对您来说很好,因为 CAST(),但它不占用 Sequence 列。
  • 除了SO我怎么没有联系方式
【解决方案2】:

我怀疑你想要的是:

ORDER BY CASE @T WHEN 'ABC' THEN Val END,
         CASE @T WHEN 'ABC' THEN Seq END,
         [Sequence];

详细说明您的尝试失败的原因。首先:

WHERE  Type = @T  ORDER BY 
 CASE 
 WHEN @T='ABC' Then Val,Seq
 ELSE Sequence END

CASE 是一个返回 标量 值的表达式。在这里,您的 WHEN 尝试返回 2 个值。这是不允许的。

 ORDER BY 
 CASE 
 WHEN @T='ABC' Then Convert(int,Val) 
 WHEN @T='ABC' Then Convert(nvarchar,Seq)
 ELSE Seq END

由于CASE 返回一个标量值,它只能返回一种数据类型。 CASE 表达式使用数据类型优先级,而int 的优先级高于nvarchar,因此Seq 将隐式转换为int;我会冒险猜测它失败了。

【讨论】:

  • 执行存储过程时,此语句给出错误:“将 nvarchar 值 'EX-02-60' 转换为数据类型 int 时转换失败”。
  • 那不会是ORDER BY 返回那个错误@ShradhaR。我的解决方案中没有隐式转换。该错误来自您未提供给我们的 SQL 中的其他地方。
  • 显式转换 Convert(nvarchar,Seq) 在这种情况下不起作用?如果没有,您能否提出更好的方法?
  • 不确定你的意思@ShradhaR。我的解决方案中没有显式或隐式转换。您得到的错误(使用我提供的ORDER BY)不是因为ORDER BY 子句。它在别的地方。
  • 如果您在问题中发布 完整 SQL 以及 DDL,那么我们也可以帮助您解决问题。或者也许将其作为一个单独的问题提出。
【解决方案3】:

ORDER BY 中的值的数据类型应始终相同。在这里你会得到转换错误,因为在第一种情况下,数据类型是 INT,而在第二种情况下,它是 Varchar。所以为了更安全的方式,您可以使用以下方法

;WITH CTE
AS
(
    SELECT
        RN_Val = ROW_NUMBER() OVER(ORDER BY Val),
        RN_Seq = ROW_NUMBER() OVER(ORDER BY Seq),
        *
        FROM YourTable
)
SELECT
    *
    FROM CTE
        ORDER BY 
        (
            CASE @T
                WHEN 'ABC' THEN RN_Val
                WHEN 'XYZ' THEN RN_Seq
            END
        )

【讨论】:

    猜你喜欢
    • 2021-07-20
    • 2021-12-13
    • 2014-11-20
    • 1970-01-01
    • 2018-10-10
    • 1970-01-01
    • 2016-01-25
    • 2021-01-21
    • 2015-06-16
    相关资源
    最近更新 更多