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
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 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.