SQL Server rownumbering and filtered results

后端 未结 3 676
死守一世寂寞
死守一世寂寞 2021-01-14 03:21

I have an application in which I need to display \"pages\" of data in a list. The basic idea is fairly common. The display shows a list of items and at the bottom of the dis

相关标签:
3条回答
  • 2021-01-14 03:31

    I wish there were something a bit more elegant than this. This is my stored proc solution. The best my lame SQL skills can conjure up.

    The OUT parameter in the parameter list is for the total rows in this set so the front end knows how many pages all together with this particular filter set.

    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
    

    So then I got started thinking. Rather than use this tricky, bug-prone proc (which by the way works fairly well), since I am in .NET, I wonder if there is a nice tight solution there.

    Now I know the original question has nothing to do with .NET, so I'm leaving the above proc available for those interested in the strict SQL solution, which, I think, works fairly well.

    So I started digging into the IQueryable interface and struck gold:

    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
        ;
    

    And that's it. The .NET approach is nice if available. The Stored Proc is great when such an API is not available.

    0 讨论(0)
  • 2021-01-14 03:36

    Something like this should do...

    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
    

    However, you should be using the column names, not '*'. I don't know what your tables look like so I can't fill that in for you.

    0 讨论(0)
  • 2021-01-14 03:43

    First of all try to use the proc instead of view and as users are asking you to have so much filtering then proc is only solution you got.Inside proc filter the data using all these filters and then generate the row_number and then show say first 100 records or like that.

    0 讨论(0)
提交回复
热议问题