簡體   English   中英

使用存儲過程對行受限的SQL查詢進行排序

[英]Sorting a row limited SQL query with stored procedures

我正在使用存儲過程來嘗試從排序的SQL查詢中獲取前幾行,其中輸入參數指定要檢索的行數和排序標准。

我已經能夠正確檢索前幾行,但是當我嘗試對結果進行排序時,它們只是顯示為使用默認條件(主鍵)進行了排序。

所以我想知道是否有人可以看一下?

USE [database]
GO
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER PROCEDURE [dbo].[x0] 
@username nvarchar(50),
@sortBy varchar(50),
@sortDirection varchar(4),
@startRow int,
@endRow int

AS
With Ordering AS(

    SELECT ROW_NUMBER() OVER (Order by
        CASE    WHEN @sortBy='datecreate' THEN 'datecreate'
                WHEN @sortBy='id' THEN 'id'
                WHEN @sortBy='DisplayName' THEN 'DisplayName'
        END,
        CASE    WHEN @sortDirection='asc' THEN 'asc'
                WHEN @sortDirection='desc' THEN 'desc'
        END) AS RowNumber,

    dbo.x1.*, dbo.x2.* 
    FROM  dbo.x1 INNER JOIN dbo.x2 ON dbo.x1.type = dbo.x2.type
    where username = @username
)
SELECT     RowNumber, *, DisplayName AS DisplayName
FROM         Ordering
Where RowNumber BETWEEN @startRow AND @endRow 

我也嘗試過將排序標准移至外部SQL查詢(其中RowNumber在@startRow和@endRow之間),但運氣不佳。

您可以這樣進行:

;WITH Ordering AS
(
   SELECT rnd  = ROW_NUMBER() OVER (ORDER BY datecreate),
          rni  = ROW_NUMBER() OVER (ORDER BY id),
          rnn  = ROW_NUMBER() OVER (ORDER BY DisplayName),
          rndd = ROW_NUMBER() OVER (ORDER BY datecreate DESC),
          rnid = ROW_NUMBER() OVER (ORDER BY id DESC),
          rnnd = ROW_NUMBER() OVER (ORDER BY DisplayName DESC),
    dbo.x1.*, dbo.x2.* 
    FROM dbo.x1 INNER JOIN dbo.x2 ON dbo.x1.type = dbo.x2.type
    where username = @username
),
x AS 
(
  SELECT RowNumber = CASE @SortDirection 
    WHEN 'asc' THEN CASE @SortBy
      WHEN 'datecreate'   THEN rnd
      WHEN 'id'           THEN rni
      WHEN 'DisplayName'  THEN rnn 
    END
    WHEN 'desc' THEN CASE @sortBy
      WHEN 'datecreate'   THEN rndd
      WHEN 'id'           THEN rnid
      WHEN 'DisplayName'  THEN rnnd
    END, *, DisplayName AS DisplayName
  FROM Ordering
)
SELECT * FROM x
WHERE RowNumber BETWEEN @startRow AND @endRow 
ORDER BY RowNumber;

但是,老實說,我認為您可以從動態SQL中獲得更好的性能(如果啟用了optimize for ad hoc workloadsoptimize for ad hoc workloads設置,則不會受到上述解決方案固有的參數嗅探問題或計划緩存膨脹的困擾):

DECLARE @sql NVARCHAR(MAX);

SET @sql = N';WITH Ordering AS
  (
    SELECT ROW_NUMBER() OVER (ORDER BY ' + @SortBy + ' '
      + @SortDirection + ') AS RowNumber,
     dbo.x1.*, dbo.x2.* 
   FROM  dbo.x1 INNER JOIN dbo.x2 ON dbo.x1.type = dbo.x2.type
   where username = @username
  )
  SELECT RowNumber, *, DisplayName AS DisplayName
   FROM Ordering
   Where RowNumber BETWEEN @startRow AND @endRow 
   ORDER BY RowNumber;';

EXEC sp_executesql @sql, 
  N'@username NVARCHAR(50), @startRow INT, @endRow INT',
  @username, @startRow, @endRow;

您的問題是查詢中使用常量。 您正在按常量字符串而不是列進行排序。 我認為您正在混合使用動態SQL和常規SQL。

要獲取名稱,您需要使用:

SELECT ROW_NUMBER() OVER (Order by
        CASE    WHEN @sortBy='datecreate' THEN datecreate
            WHEN @sortBy='id' THEN id
            WHEN @sortBy='DisplayName' THEN DisplayName
        END,

但是,由於類型沖突,這將不起作用。 您有兩個選擇。 首先,將所有類型轉換為具有正確排序順序的字符串(日期為YYYY-MM-DD,數字為零填充)。 或者,由於這是一個存儲過程,因此請為每個查詢創建一個單獨的查詢。

問題是您可能將所有內容都當作字符串來獲取,但是我仍然不確定如何獲取ASC和DESC。我認為您將需要兩個查詢,這是可行的,因為它位於存儲過程中。

我喜歡亞倫的回答,但我認為它可以改進。

WITH Ordering AS (
   SELECT ROW_NUMBER() OVER
                 (ORDER BY (case when @sortBy = 'datecreate' and @sortdirection = 'ASC'
                                 then datecreate
                            end),
                           (case when @sortBy = 'datecreate' and @sortdirection = 'DESC'
                                 then datecreate
                            end) desc,
                           (case when @sortBy = 'id' and @sortdirection = 'ASC'
                                 then id
                            end),
                           (case when @sortBy = 'id' and @sortdirection = 'DESC'
                                 then id
                            end) desc,
                           (case when @sortBy = 'DisplayName' and @sortdirection = 'ASC'
                                 then DisplayName
                            end),
                           (case when @sortBy = 'DisplayName' and @sortdirection = 'DESC'
                                 then DisplayName
                            end) desc
                 ) as rn,
          dbo.x1.*, dbo.x2.*
   FROM dbo.x1 INNER JOIN dbo.x2 ON dbo.x1.type = dbo.x2.type
   where username = @username
)

等等。 不同之處在於,只有一個row_number()調用具有更復雜的排序表達式。 除了實際用於排序的值以外,所有值都將為NULL。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM