簡體   English   中英

SQL Server rownumbering和篩選結果

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

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