Tuesday, February 3, 2009

Paged exec stored procedure



CREATE PROCEDURE [dbo].[PagedExec]
(
@sqlIn NVARCHAR(4000),
@PageIndex INT=1,
@PageSize INT=10,
@OrderBy NVARCHAR(255)='',
@OrderByType NVARCHAR(10)='ASC',
@NumberOfTotalPages int out,
@NumberOfTotalRecords int out
)
AS
SET NOCOUNT ON
DECLARE @sql NVARCHAR(4000)
DECLARE @sqlInLower NVARCHAR(4000)
DECLARE @SelectIndex int;
DECLARE @FromIndex int;
DECLARE @StartExtractIndex int;
DECLARE @EndExtractLen int;
DECLARE @WhereIndex int;
DECLARE @GroupByPresent int

Select @sqlInLower = Lower(@sqlIn)
SELECT @SelectIndex=CHARINDEX ( 'select', @sqlInLower)
SELECT @FromIndex=CHARINDEX ( 'from', @sqlInLower)
SELECT @GroupByPresent=CHARINDEX ( 'group by', @sqlInLower)
Set @StartExtractIndex = @SelectIndex + LEN('Select')
-- Add the row count stuff
-- The Order By in the ROW_NUMBER functiuonality is dummy. Overriden by the order by in select statement
Set @sql = N'Select ROW_NUMBER() OVER (ORDER BY ' + @OrderBy + N' ' + @OrderByType + N') AS RowNumber, '
Set @sql = @sql + right(@sqlIn, LEN(@sqlIn) - @StartExtractIndex)
-- Now wrap the with stuff
set @sql = N'WITH sqlWithRowNumbers AS(' + @sql + N')'
-- Find the selected fields
Declare @sqlSelectedFields NVARCHAR(2000)
Declare @sqlOriginalFields NVARCHAR(2000)
set @sqlOriginalFields = substring (@sqlIn, @StartExtractIndex, @FromIndex-@StartExtractIndex)
set @sqlSelectedFields = ' '
Declare @loop int
set @loop=1
declare @index1 int
declare @index2 int
SELECT @index1=CHARINDEX ( '''', @sqlOriginalFields)
SELECT @index2=CHARINDEX ( '''', @sqlOriginalFields, @index1+1)

while @loop=1
Begin
BEGIN TRY
Declare @FieldName NVARCHAR(500)
Set @FieldName = '"' + Substring(@sqlOriginalFields, @index1+1, @index2-@index1-1) + '"'
print @FieldName
if @FieldName <> '" "'
Begin
if @sqlSelectedFields <> ' '
set @sqlSelectedFields = @sqlSelectedFields + ', '
Set @sqlSelectedFields = @sqlSelectedFields + @FieldName
End
set @index2 = @index2+1
set @index1 = @index2;
SELECT @index1=CHARINDEX ( '''', @sqlOriginalFields, @index1+1)
if @index1=0
Begin
Set @loop=0
break;
End
SELECT @index2=CHARINDEX ( '''', @sqlOriginalFields, @index1+1)
END TRY
BEGIN CATCH
Set @loop=0
END CATCH
End
print @sqlSelectedFields
print @PageIndex
set @sql = @sql + N' Select ' + @sqlSelectedFields + N' from sqlWithRowNumbers'
set @sql = @sql + ' Where RowNumber between '
set @sql = @sql + STR(((@PageIndex - 1) * @PageSize) + 1)
set @sql = @sql + N' and '
set @sql = @sql + STR(@PageIndex*@PageSize)
EXEC sp_executesql @sql
DECLARE @ParmDefinition NVARCHAR(500)
SET @ParmDefinition = N'@NumberOfTotalRecords int OUTPUT'
if @GroupByPresent>0
Set @sql = N'select @NumberOfTotalRecords = count(*) from (Select Count(*) as cnt ' + right(@sqlIn, LEN(@sqlIn) - @FromIndex+2) + ') as grpcnt'
else
Set @sql = N'Select @NumberOfTotalRecords = Count(*) ' + right(@sqlIn, LEN(@sqlIn) - @FromIndex+2)
EXEC sp_executesql @sql, @ParmDefinition, @NumberOfTotalRecords out
Declare @floatTemp float
Declare @floatTemp1 float
Declare @floatTemp2 float
-- If we do not use temp float variables, the CEILING function does not work, down below.
Set @floatTemp1 = @NumberOfTotalRecords
Set @floatTemp2 = @PageSize
set @floatTemp = CEILING(@floatTemp1 / @floatTemp2)
Set @NumberOfTotalPages = CEILING(@floatTemp)
if @NumberOfTotalRecords is NULL
set @NumberOfTotalRecords= 0
if @NumberOfTotalPages is NULL
set @NumberOfTotalPages= 0
print @NumberOfTotalRecords
print @NumberOfTotalPages
RETURN 0