0

我在 SQL Server 2012 中的存储过程有问题。

首先是表:

    [ProductId] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](100) NOT NULL,
    [Description] [nvarchar](500) NOT NULL,
    [Category] [nvarchar](50) NOT NULL,
    [Price] [decimal](16, 2) NOT NULL,

和存储过程:

    CREATE procedure [dbo].[GetProductsPaging]
    (@PageOffset bigint=0, 
     @PageSize bigint=5,  
     @OrderBy varchar(30) = 'ProductId',  
     @DescOrder bit = 0) 
    AS
BEGIN
    IF @DescOrder = 0
    BEGIN
        SELECT * FROM [dbo].Products
        ORDER BY
            CASE @OrderBy
                WHEN 'ProductId' THEN ProductId
                WHEN 'Name' THEN Name
                WHEN 'Category' THEN Category
                WHEN 'Price' THEN Price
                ELSE NULL
            END ASC
        OFFSET @PageOffset ROWS
        FETCH NEXT @PageSize ROWS ONLY
    END
    ELSE 
    BEGIN
        SELECT * FROM [dbo].Products
        ORDER BY
            CASE @OrderBy
                WHEN 'ProductId' THEN ProductId
                WHEN 'Name' THEN Name
                WHEN 'Category' THEN Category
                WHEN 'Price' THEN Price
                ELSE NULL
            END DESC
        OFFSET @PageOffset ROWS
        FETCH NEXT @PageSize ROWS ONLY
    END
END

当我这样执行时

EXEC dbo.GetProductsPaging 0, 0 ,'Price', 0

该程序工作得很好,但是当使用它时

EXEC dbo.GetProcedurePaging 0, 0, 'Name', 0

我收到这个错误

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

有人可以帮我吗?感谢您的任何回答。

4

3 回答 3

1

我想是因为你的CASE表情。您的案例的第一行是WHEN 'ProductId' THEN ProductId,因此它将所有其他字段转换为与ProductId. 它适用于 Priceas Price 可以转换为 INT 但失败为 Name as it encounters an error converting data type nvarchar to numeric

试试这个以获得相同的结果:

CASE @OrderBy
        WHEN 'ProductId' THEN RIGHT(100000000 + ProductId, 8)
        WHEN 'Name' THEN Name
        WHEN 'Category' THEN Category
        WHEN 'Price' THEN RIGHT(100000000 + Price, 8)
        ELSE NULL
     END ASC

Right()函数用于获取 ProductId 和 Price 列的数字和 varchar 值的相同顺序。请对Order by DESC部分应用相同的更改。

于 2013-11-03T16:15:00.403 回答
1
ORDER BY
        CASE @OrderBy
            WHEN 'ProductId' THEN ProductId
            WHEN 'Name' THEN Name
            WHEN 'Category' THEN Category
            WHEN 'Price' THEN Price
            ELSE NULL
        END ASC

当您混合数字和非数字分支时将不起作用。表达式的类型CASE是具有最高数据类型优先级的分支的类型。您可以使用

ORDER BY
        CASE @OrderBy
            WHEN 'ProductId' THEN ProductId
            WHEN 'Name' THEN Name
            WHEN 'Category' THEN Category
            WHEN 'Price' THEN Price
            ELSE CAST(NULL AS SQL_VARIANT)
        END ASC

或者

ORDER  BY CASE
            WHEN 'ProductId' = @OrderBy THEN ProductId
          END,
          CASE
            WHEN 'Name' = @OrderBy THEN Name
          END,
          CASE
            WHEN 'Category' = @OrderBy THEN Category
          END,
          CASE
            WHEN 'Price' = @OrderBy THEN Price
          END 

如果你使用OPTION (RECOMPILE)最后一个,你可能会得到一个更好的计划。

于 2013-11-03T16:17:06.517 回答
1

案例中的所有输出选项必须具有相同的数据类型,我认为案例决定了从第一个选项使用什么输出类型,并尝试将其他值转换为该类型,在您的情况下,第一个和最后一个选项,( ProductId 和 Price),是数字,但其他是字符...修改大小写(在两个地方)如下:

CASE @OrderBy
  WHEN 'ProductId' THEN str(ProductId, 7, 0) 
  WHEN 'Name' THEN Name
  WHEN 'Category' THEN Category
  WHEN 'Price' THEN str(Price, 16,4)
  ELSE NULL
END ASC

然而,意识到任何对价格的排序现在都将基于字符进行,即 100 将在 20 之前

于 2013-11-03T16:18:08.323 回答