• Hello all,

    After benefitting from the code examples and explanations above, I thought I'd make a contribution.

    Below is a generic stored procedure that will retrieve the page of rows based on the parameters fed to it. It determines whether the table called for is in fact a table or a view. If it's a table, it uses the sys-tables to get the total row count (thanks to a post above this one!) and if it's a view, it uses the original strategy of calculating the inverse row # for a given row. I didn't compute the total rows because I thought whatever was calling it would only have to make the computation once rather than once-per-row if I had done it here.

    Before the Efficiency Police hall me away, this was slapped together as a proof of concept and is not (in any way) presented as the best way of doing this. And there is a rule. Your ORDER-BY clause must include ASC where appropriate. This made inverting the order-by merely ugly, down from absolutely hideous.

    [Code]

    set ANSI_NULLS ON

    set QUOTED_IDENTIFIER ON

    go

    ALTER PROCEDURE [dbo].[GetPage]

    -- Add the parameters for the stored procedure here

    (

    @TableName varchar(1000)

    ,@Fields varchar(1000)

    ,@OrderBy varchar(1000)

    ,@StartPosition int

    ,@PageLen int

    )

    AS

    Begin

    DECLARE

    @strSQL varchar(max)

    ,@RowCount int

    ,@RightNow DATETIME

    ,@TableType varchar(20)

    ,@RevOrderBy varchar(1000)

    Set @RightNow=GETDATE()

    Set @PageLen = @PageLen - 1

    if not EXISTS (select * from INFORMATION_SCHEMA.tables where table_name = @TableName)

    begin

    Select 'Table/View not found' as Error

    return (-1)

    end

    select @TableType = TABLE_TYPE from INFORMATION_SCHEMA.tables where table_name = @TableName

    if @TableType = 'BASE TABLE'

    begin

    SELECT @RowCount=P.Rows

    FROM sys.partitions P

    INNER JOIN sys.indexes I ON (P.object_id = I.object_id) AND (P.index_id = I.index_id)

    INNER JOIN sys.objects O ON (P.object_id = O.object_id)

    WHERE (I.type IN(0,1)) AND (O.name = PARSENAME(@TableName, 1) AND

    O.[schema_id] = IsNull(SCHEMA_ID(PARSENAME(@TableName, 2)), O.[schema_id]))

    ORDER BY O.name

    set @strSQL =' SELECT * ' +

    ', ' + convert(varchar(10),@RowCount) + ' as [RowCount] ' +

    ' FROM (SELECT ' + @Fields + ', ROW_NUMBER() OVER(ORDER BY ' + @OrderBy + ') AS RowNumber ' +

    ' FROM [' + @TableName + ']) as [' + @TableName + '_A] ' +

    ' WHERE RowNumber BETWEEN ' + convert(varchar(10),@StartPosition) +

    ' AND ' + convert(varchar(10),(@StartPosition + @PageLen)) + ' ORDER BY RowNumber'

    end

    else

    begin

    set @RevOrderBy = upper(@OrderBy) + ','

    set @RevOrderBy = replace(replace(replace(@RevOrderBy ,' ASC,',' ~A,'),' DESC,',' ASC,'),' ~A',' DESC')

    set @RevOrderBy = left(@RevOrderBy ,len(@RevOrderBy)-1)

    set @strSQL =' SELECT *' +

    ' FROM (' +

    'SELECT ' + @Fields + ', ROW_NUMBER() OVER(ORDER BY ' + @OrderBy + ') AS RowNumber, ' +

    ' ROW_NUMBER() OVER(ORDER BY ' + @RevOrderBy + ') AS RowNumberInverse ' +

    ' FROM [' + @TableName + ']) as [' + @TableName + '_A] ' +

    ' WHERE RowNumber BETWEEN ' + convert(varchar(10),@StartPosition) +

    ' AND ' + convert(varchar(10),(@StartPosition + @PageLen)) + ' ORDER BY RowNumber'

    end

    --SELECT SQL=@strSQL

    EXEC(@strSQL)

    End

    [/code]

    Enjoy!