2011-11-01 42 views
1

此SQL语句在ORDER BY'+ @SortField +''+ @SortOrder +'部分中被标记在SQL Server中。任何想法如何解决?SQL Server中变量的分页排序

ALTER PROC [sbuser].[sp_MemberMailList ] 
@MemberMailID bigint = null, 
@FromMemberID bigint = null, 
@ToMemberID bigint = null, 
@Subject varchar(150) = null, 
@Message varchar(8000) = null, 
@FromDeletedFlag bit = null, 
@ToDeletedFlag bit = null, 
@FromArchivedFlag bit = null, 
@ToArchivedFlag bit = null, 
@ReadFlag bit = null, 
@SQL nvarchar(4000) = null, 
@SortField varchar(100) = null, 
@SortOrder varchar(25) = null, 
@NotificationSent bit = null, 
@MemberID bigint = null, 
@OnHold bit = 0, 
@SpecialMail varchar(1) = 'N', 
@PageSize float = null, 
@PageNum int = 1, 
@TotalPages float = null, 
@StartDate datetime = null, 
@EndDate datetime = null, 
@MODE varchar(50) 

AS 

IF @MODE = 'INBOX-MAIL' 
BEGIN 
    SELECT @TotalPages = COUNT(*)/@PageSize 
    FROM MemberMail a 
    INNER JOIN Member b ON b.MemberID = a.FromMemberID 
    WHERE a.ToMemberID = @ToMemberID 
    AND a.ToDeletedFlag = 0 
    AND a.OnHold = 0 
    AND a.ToArchivedFlag = 0; 

    WITH InMails AS 
    (
     SELECT ROW_NUMBER() OVER(ORDER BY ' + @SortField + ' ' + @SortOrder + ') AS RowNum, 
     a.MemberMailID, 
     a.FromMemberID, 
     a.Subject, 
     a.CreateDate, 
     b.UserName, 
     a.ToReadFlag, 
     b.Firstname, 
     b.Lastname, 
     b.MemberDisplayName AS DisplayName 
     FROM MemberMail a 
     INNER JOIN Member b ON b.MemberID = a.FromMemberID 
     WHERE a.ToMemberID = @ToMemberID 
     AND a.ToDeletedFlag = 0 
     AND a.OnHold = 0 
     AND a.ToArchivedFlag = 0 
    ) 
    SELECT * 
    FROM InMails 
    WHERE RowNum BETWEEN (@PageNum - 1) * @PageSize + 1 AND @PageNum * @PageSize 
    ORDER BY CreateDate DESC 
END 

任何帮助,将不胜感激..

非常感谢

回答

1

您无法指定字段或使用变量排序方向。整个SQL语句需要是一个动态字符串来执行此操作。

所以

SELECT ROW_NUMBER() OVER(
    ORDER BY [field expression] asc|desc) AS RowNum 

是好的,因为是

exec('SELECT ROW_NUMBER() OVER(' + 
    'ORDER BY ' + @SortField + ' ' + @SortOrder + ') AS RowNum ...') 

SELECT ROW_NUMBER() OVER(
    ORDER BY ' + @SortField + ' ' + @SortOrder + ') AS RowNum 

不能在SQL查询编译器进行处理。

+0

任何想法如何解决这个问题?请真的在这里使用帮助。 – neojakey

+0

@neojakey - 前两个选项中的任何一个都可以工作。基本上你在'order by'中有静态字段,或者整个语句必须是一个动态字符串。这是因为你选择'order by'可以完全改变查询计划及其优化方式,所以在缓存SQL时没有任何价值。 – Keith

+0

@neojakey - 有一种方法可以解决这个问题,但它很讨厌。你的sproc只能有你的'MemberMail'或'Member'表中的排序字段,所以你可以为每个可排序字段重复整个语句。这将是非常难看的代码,但会给出它可以缓存的SQL查询计划。 – Keith

1
SELECT ROW_NUMBER() OVER(ORDER BY ' + @SortField + ' ' + @SortOrder + ') AS RowNum, 
            ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ 
            string #1    string #2 

                 ^---no operator 

除非你有一个外部串您的代码示例中没有显示,则无法建立order by子句喜欢这个。你有两个不同的引用字符串,之间有空格。

1

它看起来像你试图动态改变ORDER BYROW_NUMBER()排名函数的字段。你不能像你想要的那样去做。

您需要使用动态SQL来完成您正在尝试的操作。您应该阅读The Curse and Blessings of Dynamic SQL以更好地理解机制,以及如何保护自己免受SQL注入的侵害。

如果由于某种原因您不想使用动态SQL,您可以生成一个巨大的case语句。例如下面的这个例子取自gbn对Dynamic order direction的回答。

SELECT 
    Columns you actually want 
FROM 
    (
    SELECT 
     Columns you actually want, 
     ROW_NUMBER() OVER (ORDER BY AddedDate) AS AddedDateSort, 
     ROW_NUMBER() OVER (ORDER BY Visible) AS VisibleSort, 
     ROW_NUMBER() OVER (ORDER BY AddedBy) AS AddedBySort, 
     ROW_NUMBER() OVER (ORDER BY Title) AS TitleSort 
    FROM 
     myTable 
    WHERE 
     MyFilters... 
    ) foo 
ORDER BY 
    CASE @OrderByColumn 
     WHEN 'AddedDate' THEN AddedDateSort 
     WHEN 'Visible' THEN VisibleSort  
     WHEN 'AddedBy' THEN AddedBySort 
     WHEN 'Title' THEN TitleSort 
    END * @multiplier; 

如果你这样做,你应该注意性能问题,因为索引可能不会用于排序。

+0

不错的解决方案 - 你可以用一个子查询进一步简化它,其中'case'开关是一个选择。然后你有'row_number()'函数。 – Keith