【问题标题】:sql orderby conversion error when case is used使用大小写时按转换错误排序的sql
【发布时间】:2011-09-02 15:25:35
【问题描述】:

我有以下问题。运行时我收到

将数据类型 nvarchar 转换为数值时出错。

仅当@sortorder = 1-1 按名称排序时才会发生这种情况。但是,如果删除了 case 语句并且只使用了order by Name asc,则查询运行不会出错。

谁能解释这里发生了什么?谢谢。

DECLARE @SortOrder INT = 1

CREATE TABLE #Results
(
ID INT IDENTITY(1,1),

NameID INT,

Expected NUMERIC(5,1),

Actual NUMERIC(5,1)

)

SELECT Name, Expected, Actual, ID 

FROM (

      SELECT ISNULL(NULLIF(Words.Word, ''), Name.Primary) AS [Name], #Results.Expected, #Results.Actual, #Results.NameID 
    FROM #Results
    INNER JOIN Name ON Name.ID  = #results.NameID 
    LEFT OUTER JOIN Words ON Name.WordID = Words.WordID 
        AND Words.LanguageID = 0
    UNION
    SELECT 'AVG' AS Name,
            CAST(((SUM(#Results.Expected))/COUNT(#Results.ID)) AS NUMERIC(5,1)) AS [Expected],
            CAST(((SUM(Actual))/COUNT(ID)) AS NUMERIC(5,1))AS [Actual],
            -9999 as [ID]
    FROM #Results 
) AS Results

ORDER BY 
    CASE @SortOrder

        WHEN 1 THEN Name    
        WHEN 2 THEN Expected
        WHEN 3 THEN Actual      
        END ASC,    
    CASE @SortOrder 
        WHEN -1 THEN Name   
        WHEN -2 THEN Expected
        WHEN -3 THEN Actual
        END DESC

【问题讨论】:

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


    【解决方案1】:

    您需要为每种可能的数据类型使用单独的 case 表达式。

    ORDER BY 
        CASE @SortOrder
            WHEN 1 THEN Name END,
        CASE @SortOrder
            WHEN 2 THEN Expected
            WHEN 3 THEN Actual      
            END,    
        CASE @SortOrder 
            WHEN -1 THEN Name END DESC,
        CASE @SortOrder   
            WHEN -2 THEN Expected
            WHEN -3 THEN Actual
            END DESC;
    

    【讨论】:

      【解决方案2】:

      作为一般规则,永远不要使用这样的东西。使用三个单独的查询:

      if @SortOrder = 1 then
      select ... order by Name;
      else if @SortOrder = 2 then
      select ... order by Expected
      else if @SortOrder = 3 then
      select ... order by Actual;
      

      您现在正在做的是 100% 肯定的方法,以拒绝 SQL Server 查询优化器任何体面的机会提出一个有效的计划:生成的计划必须适用于 任何 值@SortOrder 变量,因此它必须进行排序,即使索引会满足约束顺序。有关该主题的更长时间的讨论,请阅读Dynamic Search Conditions in T-SQL

      现在,在您的情况下,来自#temp 表的数据对于将堆栈较高的情况分开更为重要。由于#temp 表支持索引,因此在创建#temp 表时将适当的聚集索引添加到它本身。这意味着根据要求为NameExpectedActual 使用特定的、单独的#temp 表。

      【讨论】:

      • 我想我宁愿动态 SQL 和 exec sp_executeSQL 仍然有单独的计划是可能的,而不是按照建议使用 IF 并且必须维护 6 个不同版本的基本查询。
      • 谢谢。你不仅解决了我的问题,还解释了你的解决方案。你先生/妈妈是我来这里寻求帮助的原因
      • 另一方面是考虑可维护性 - 如果 SELECT 很大或很复杂,那么您只需将 CASE 语句拆分为变量类型。与使用动态 SQL 的任何长度查询一样,难以维护对每个潜在列的重复查询。我刚刚通过删除动态 sql 以支持 CASE 语句,并且在测试中,CASE 语句的速度要快几个数量级。
      【解决方案3】:

      CASE 表达式作为一个整体将被强制转换为带有highest precedence 的分支的数据类型。

      您可以尝试强制转换为 sql_variant,因为它的优先级高于除 UDT 之外的所有内容,并且应该正确排序。

      【讨论】:

      • ... 或确保CASE 语句中引用的所有不同列的类型相同——无论是VARCHAR 还是INT——只是不要混合不同的类型。 ...
      • 感谢您的格式化,感谢您的回答,成功! booooooo 不能再接受 5 分钟
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-25
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 2011-12-29
      • 2023-04-11
      相关资源
      最近更新 更多