[英]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 workloads
的optimize 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.