具有多列的Order by子句的语法不正确

问题描述 投票:1回答:3

如何在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时转换失败。

sql sql-server tsql sql-order-by case
3个回答
7
投票

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

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'它将抛出以下错误

Msg 245 Level 16 State 1 Line 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


1
投票

我怀疑你追求的是:

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;而且我猜想那次失败了。


0
投票

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
        )
© www.soinside.com 2019 - 2024. All rights reserved.