[英]SQL Server rownumbering and filtered results
我有一個應用程序,我需要在列表中顯示數據的“頁面”。 基本思想相當普遍。 顯示屏顯示項目列表,顯示屏底部是某種控件,可讓您轉到下一個“頁面”數據。
一切都很好。 我有這個工作。
以下是我用於支持“下一步”行為的視圖中的SQL。
CREATE VIEW CampaignParticipants AS
SELECT row_number() OVER (ORDER BY TPT.LastName, TPT.FirstName, TPT.DoB) AS RowNumber
,CGP.*
,TPT.*
FROM tblCampaignGEDPush CGP
JOIN tblParticipants TPT
ON CGP.PartID = TPT.PartID
這是我如何使用VIEW
SELECT *
FROM CampaignParticipants
WHERE RowNumber >= 0
AND RowNumber <= 100
這模擬了從VIEW中抓取100個結果的“第一頁”。 頁面通過每組結果只是桃子。
太棒了..但是:
正如你們中的一些人所知道的那樣,這可能是有缺陷的。 如果我想在TPT.LastName like 'R%'
上搜索TPT.LastName like 'R%'
並獲得第一組結果,我注定要失敗。
我想要開始查看RowNumber = 0
,停在RowNumber = 100
,但“R”結果可能遠遠超出該范圍。 Upshot:列表返回空白。
它變得更加棘手:用戶希望能夠“過濾”LastName,FirstName,DoB,Location,Phone,Zip等等。
**編輯:我無法將過濾器放在“內部”查詢上,因為它在視圖中,並且過濾器可以任意更改
任何人都有任何想法如何讓這個結果集在過濾的結果集上有一個row_number()
?
這樣的事應該做......
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY LastName, FirstName, DoB) AS __RN
FROM CampaignParticipants
WHERE LastName LIKE 'R%') innerData WHERE __RN BETWEEN 1 and 100
但是,您應該使用列名,而不是'*'。 我不知道你的桌子是什么樣的,所以我不能為你填寫。
首先嘗試使用proc而不是視圖,因為用戶要求你有這么多過濾,然后proc只是你得到的解決方案.Inside proc使用所有這些過濾器過濾數據,然后生成row_number然后顯示說首先100記錄或類似的。
我希望有一些比這更優雅的東西。 這是我的存儲過程解決方案。 我最蹩腳的SQL技能可以讓人聯想到。
參數列表中的OUT參數用於此集合中的總行數,因此前端知道所有這些特定過濾器集合的頁面數量。
CREATE PROC [dbo].[procCampaignGEDPushSelect]
@LastName VARCHAR(50) = null
,@FirstName VARCHAR(50) = null
,@Location VARCHAR(255) = null
,@DoB DateTime = null
,@Zip VARCHAR(50) = null
,@Phone VARCHAR(50) = null
,@Email VARCHAR(255) = null
,@Gender VARCHAR(20) = null
,@IsGED Bit = 0
,@IsBTT Bit = 0
,@IsOACE Bit = 0
,@Completed Bit = 0
,@TotalCount INT OUT
AS
BEGIN
SELECT @LastName = @LastName + '%'
SELECT @FirstName = @FirstName + '%'
SELECT @Location = @Location + '%'
SELECT @Zip = @Zip + '%'
SELECT @Phone = @Phone + '%'
SELECT @Email = @Email + '%'
SELECT @Gender = @Gender + '%'
SELECT row_number() OVER (ORDER BY LastName, FirstName, DoB) AS RowNumber
, TPT.LastName
, TPT.FirstName
, TPT.WF1Site
, TPT.DOB
, TPT.Zip
, TPT.Telephone
, TPT.CellPhone
, TPT.Email
, TPT.Gender
, TPT.IsBTT
, TPT.IsGED
, TPT.IsOACE
, TPT.IsSRS
,CGP.*
FROM tblCampaignGEDPush CGP
JOIN tblParticipants TPT
ON CGP.PartID = TPT.PartID
WHERE 1=1
AND 1 = (CASE WHEN @LastName IS NOT NULL THEN (CASE WHEN TPT.LastName LIKE @LastName THEN 1 ELSE 0 END) ELSE 1 END)
AND 1 = (CASE WHEN @FirstName IS NOT NULL THEN (CASE WHEN TPT.FirstName LIKE @Firstname THEN 1 ELSE 0 END) ELSE 1 END)
AND 1 = (CASE WHEN @Location IS NOT NULL THEN (CASE WHEN TPT.WF1Site LIKE @Location THEN 1 ELSE 0 END) ELSE 1 END)
AND 1 = (CASE WHEN @Zip IS NOT NULL THEN (CASE WHEN TPT.Zip LIKE @Zip THEN 1 ELSE 0 END) ELSE 1 END)
AND
( 1 = (CASE WHEN @Phone IS NOT NULL THEN (CASE WHEN TPT.Telephone LIKE @Phone THEN 1 ELSE 0 END) ELSE 1 END)
OR 1 = (CASE WHEN @Phone IS NOT NULL THEN (CASE WHEN TPT.CellPhone LIKE @Phone THEN 1 ELSE 0 END) ELSE 1 END)
)
AND 1 = (CASE WHEN @Email IS NOT NULL THEN (CASE WHEN TPT.Email LIKE @Email THEN 1 ELSE 0 END) ELSE 1 END)
AND 1 = (CASE WHEN @Gender IS NOT NULL THEN (CASE WHEN TPT.Gender LIKE @Gender THEN 1 ELSE 0 END) ELSE 1 END)
AND 1 = (CASE WHEN @DoB IS NOT NULL THEN (CASE WHEN TPT.DoB = @DoB THEN 1 ELSE 0 END) ELSE 1 END)
AND 1 = (CASE WHEN @IsGED != 0 THEN (CASE WHEN TPT.IsGED = 1 THEN 1 ELSE 0 END) ELSE 1 END)
AND 1 = (CASE WHEN @IsBTT != 0 THEN (CASE WHEN TPT.IsBTT = 1 THEN 1 ELSE 0 END) ELSE 1 END)
AND 1 = (CASE WHEN @IsOACE != 0 THEN (CASE WHEN TPT.IsOACE = 1 THEN 1 ELSE 0 END) ELSE 1 END)
AND 1 = (CASE WHEN @Completed != 0 THEN (CASE WHEN CGP.Completed = 1 THEN 1 ELSE 0 END) ELSE 1 END)
ORDER BY TPT.LastName
, TPT.FirstName
, TPT.DoB
SELECT @TotalCount = @@ROWCOUNT
END
所以我開始思考了。 而不是使用這個棘手的,容易出錯的過程(順便說一下工作得很好),因為我在.NET中,我想知道那里是否有一個很好的緊密解決方案。
現在我知道原始問題與.NET無關,所以我將上述proc留給那些對嚴格SQL解決方案感興趣的人,我認為這些解決方案運行得相當好。
所以我開始深入研究IQueryable界面並打出金牌:
IQueryable<queryParticipant> qparticipant = db.queryParticipants.AsQueryable();
...
qparticipant = qparticipant.Where( ... any filter you choose );
...
return qparticipant
.OrderBy( p => p.LastName )
.OrderBy( p => p.FirstName )
.OrderBy( p => p.DOB )
.Select( ... whatever you like ... )
.Skip( StartRecordNumber ) // This is the trick! Start the query here..
.Take( PageSize ) // Take only as many as you need
;
就是這樣。 如果可用,.NET方法很好。 當這樣的API不可用時,Stored Proc很棒。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.