存储过程中的动态ORDER BY未按预期工作

时间:2016-08-15 06:03:49

标签: sql sql-server sql-server-2008

这是我搜索用户上传的图片库的存储过程:

ALTER PROCEDURE dbo.sp_SearchGallery
(
@strSearchTerm NVARCHAR(50) = NULL,
@strCategory NVARCHAR(50) = NULL,
@nUserId INT = NULL,
@nSortBy INT = 0,
@nSortDesc BIT = 0,
@nPage INT = 1,
@nPageSize INT = 10
) AS

SET NOCOUNT ON

DECLARE @nSortSwitch INT = 1
IF @nSortDesc = 1 BEGIN
    SET @nSortSwitch = -1
END

DECLARE @FirstRec INT = (@nPage - 1) * @nPageSize
DECLARE @LastRec INT = (@nPage * @nPageSize + 1)

; WITH rowQueryResults AS
(
    SELECT *, ROW_NUMBER() OVER
    (
        ORDER BY
            CASE @nSortBy
                WHEN 0 THEN Date
                WHEN 1 THEN Title
                WHEN 2 THEN Description
                WHEN 3 THEN ID
            END
    ) AS RowNum
    FROM dbo.GalleryItems
    WHERE ((@strSearchTerm IS NULL OR Title LIKE '%' + @strSearchTerm + '%') OR
          (@strSearchTerm IS NULL OR Description LIKE '%' + @strSearchTerm + '%')) AND
          (@nUserId IS NULL OR UserId = @nUserId) AND
          (@strCategory IS NULL OR Category LIKE '%' + @strCategory + '%') AND
          (Accepted=1)
)
SELECT *
FROM rowQueryResults
WHERE RowNum > @FirstRec AND RowNum < @LastRec
ORDER BY RowNum*@nSortSwitch

RETURN

我可以将@nSortBy设置为0,这可以正常工作。我可以将它设置为3,这也可以正常工作,但是一旦我将其设置为1或2,它就会崩溃,异常Conversion failed when converting date and/or time from character string.

我假设它正在尝试将TitleDescription转换为DateTime进行排序。 ID之所以有效,是因为它是一个整数,因此可以安全地转换为DateTime(显然不是我想要它做的事)

但是,为什么会那样做呢?我怎么做它所以它做一个strcmp而不是时间比较订购?

2 个答案:

答案 0 :(得分:3)

这与数据优先级有关,当您遇到不同数据类型之间的情况时,SQL会将较低数据类型转换为最高数据类型。尝试这样,以便您的最高数据类型变为varchar,因此它不会尝试将标题和描述转换为日期时间。

ORDER BY
        CASE @nSortBy
            WHEN 0 THEN convert(varchar, Date)
            WHEN 1 THEN Title
            WHEN 2 THEN Description
            WHEN 3 THEN convert(varchar, ID)
        END

https://msdn.microsoft.com/en-us/library/ms190309.aspx

答案 1 :(得分:3)

有一个简单的替代方案,不需要转换:

ORDER BY
        CASE WHEN @nSortBy = 0 THEN Date END,
        CASE WHEN @nSortBy = 1 THEN Title END,
        CASE WHEN @nSortBy = 2 THEN Description END,
        CASE WHEN @nSortBy = 3 THEN ID END

这是一个奇怪的小技巧。从理论上讲,它按排名顺序在四个字段上进行ORDER BY。实际上虽然@nSortBy只能有一个值,所以实际上只对其中的四个排序中的一个进行了操作。