2011-11-01 84 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