分页存储过程


ROW_NUMBER的用法
select * from
(
select CustomerId, ROW_NUMBER() OVER (order by CustomerId) 
as Pos from CRMCustomer
as T
where T.Pos BETWEEN 1 and 10

sql2000
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go

 

ALTER PROCEDURE [dbo].[PageSplit]
    
-- Add the parameters for the stored procedure here
    @SQL Nvarchar(max),
    @Order Nvarchar(
20),
    @CurPage 
int,
    @PageRows 
int,
    @TotalRecorder 
int output
AS
BEGIN
    
-- SET NOCOUNT ON added to prevent extra result sets from
DECLARE @Str nVARCHAR(
4000),@ID VARCHAR(255),@ExceSQL VARCHAR(255)
set @ID = @Order


WITH tmp AS (SELECT 
* FROM INFO)
        select @TotalRecorder
=COUNT(*) from tmp

SET @Str
='SELECT   TOP '+CAST(@PageRows AS VARCHAR(20))+' * FROM ('+@SQL+') T WHERE T.'+@ID+' NOT IN
(SELECT   TOP '+CAST((@PageRows*(@CurPage-1)) AS VARCHAR(20))+' '+@ID+' FROM ('+@SQL+') T9 ORDER BY '+@Order+') ORDER BY '+@Order

PRINT @Str

EXEC sp_ExecuteSql @Str
   
END

sql2005

ALTER PROCEDURE [dbo].[PageSplit]
    
-- Add the parameters for the stored procedure here
    @SQL Nvarchar(max),
    @Order Nvarchar(
20),
    @CurPage 
int,
    @PageRows 
int,
    @TotalRecorder 
int output
AS
BEGIN
    
-- SET NOCOUNT ON added to prevent extra result sets from
    SET NOCOUNT ON;
    declare @ExceSQL nvarchar(max)

   
    
--設置開始行號
    declare  @start_row_num AS 
int
    SET @start_row_num 
= (@CurPage - 1* @PageRows
  
    
--設置標識語句
    
--declare @RowNumber nvarchar(100)
    
--set @RowNumber = ', ROW_NUMBER() OVER(ORDER BY ' + @Order + ') as RowNumber from '

    
--set @SQL = Replace(@SQL,' from ',@RowNumber)
    
set @SQL = 'select * ,ROW_NUMBER() OVER(ORDER BY TT.'  + @Order + ') as RowNumber from (' + @SQL + ') TT'
    
--獲得總記錄數
    
set @ExceSQL = 'WITH tmp AS (' + @SQL + ')
        select @TotalRecorder=max(RowNumber) from tmp'

    execute sp_executesql @ExceSQL,N
'@TotalRecorder int output',@TotalRecorder output


    
--設置查詢語句
    
set @ExceSQL = 'WITH tmp AS (' + @SQL + ')
        select * from tmp where RowNumber > ' + Convert(nvarchar,@start_row_num)
        + ' And RowNumber <= ' + Convert(nvarchar,@start_row_num+@PageRows)

    execute(@ExceSQL)
   
END

 Oracle

其一

CREATE OR REPLACE PACKAGE SplitPage  is
  type Splitlist 
is REF CURSOR;
  PROCEDURE SPLITDATA
  (
  SqlStr 
in varchar2,
  pagesize 
in integer,
  PageIndex 
in integer,
  RecordCount 
out integer,
  retunlist 
out Splitlist
  );
end SplitPage;
/
CREATE OR REPLACE PACKAGE body SplitPage
IS Procedure SplitData
 (
     
----IN------
     
-- 传入进行分页的SQL语句
     SqlStr 
in varchar2,
     
-- 页大小
     PageSize 
in integer,
     
-- 需要获取的当前页码
     PageIndex 
in integer,
     
----OUT------
     
-- 返回记录总数
     RecordCount 
out integer,
     
--返回执行后的游标(数据集)
     RetunList 
out Splitlist
)
AS
   v_splitsql varchar2(
1000); --正式用来查询的SQL语句
   v_exutteSQL varchar2(
1000);--用来存储Select SQL语句中从From开始的以后所有字符
   v_listSizeSQL varchar2(
1000);--用来组织获取数据统计SQL
   v_CurrPage 
int--当前页码
   
--v_MaxSize int;--最大行
   v_MinLine 
int--最小行
   v_MaxLine 
int--最大行
   v_MaxPage integer; 
--最大页
begin
 
--修改SQL语句,插入Rownum字段作为ID
 select SubStr(trim(SqlStr),
7,1000) into v_exutteSQL from dual;
 v_splitsql:
='select rownum splitID,'||v_exutteSQL;
 
--清空exutteSQL
 v_exutteSQL:
='';
 select SubStr(SqlStr,instr(SqlStr,
'from'),1000) into v_exutteSQL from dual;
 
--组织新的SQL语句
 v_listSizeSQL:
='select count(*)  '||v_exutteSQL;
 
--执行SQL语句
 execute immediate v_listSizeSQL into RecordCount;
 
--取得最大页数
 v_MaxPage :
= ceil(RecordCount/PageSize);
 
--检查当前页码是否符合要求
 
if PageIndex>v_MaxPage then
    v_CurrPage:
=v_MaxPage;
 
else
     v_CurrPage:
=PageIndex;
 end 
if;
 
--取得当前最小行数
 
if (v_CurrPage-1>0) then
    v_MinLine:
=(v_CurrPage-1)*PageSize;
  
else
    v_MinLine:
=0;
 end 
if;
 
--取得当前最大行数
 v_MaxLine:
=v_CurrPage*PageSize;
 v_splitsql:
='select * from ('||v_splitsql||') where splitID>'||v_MinLine||' and splitID<='||v_MaxLine;

 open RetunList 
for v_splitsql;

END SplitData;
END SplitPage;
/

其二

create or replace package PKG_PageSplit is
    TYPE mytype IS REF CURSOR;
    Procedure GetRecords
     (
       p_PageSize Int, 
--每页记录数
       p_PageIndex Int, 
--当前页码,从 1 开始
       p_SqlSelect Varchar2, 
--查询语句,含排序部分
       p_RecordIndex    Int Default 
0,--单条记录ROWNUM索引编号:如果值为0则返回分页的记录集,如果值不为0则返回具体的记录
       p_OutRecordCount Out Int, 
--返回总记录数
       p_OutPageCount Out Int, 
--返回总的页数
       p_OutCursor 
out mytype  --返回记录集
     );
end PKG_PageSplit;
/
create or replace package body PKG_PageSplit
is
   Procedure GetRecords(
    p_PageSize Int, 
--每页记录数
    p_PageIndex Int, 
--当前页码,从 1 开始
    p_SqlSelect Varchar2, 
--查询语句,含排序部分
    p_RecordIndex    Int Default 
0,--单条记录ROWNUM索引编号:如果值为0则返回分页的记录集,如果值不为0则返回具体的记录
    p_OutRecordCount Out Int, 
--返回总记录数
    p_OutPageCount Out Int, 
--返回总的页数
    p_OutCursor 
out mytype --返回记录集
)
as
v_sql Varchar2(
8000);
v_count Number; v_lowRownum Number; v_heiRownum Number;
v_selectfields Varchar2(
4000);       --要查询的字段
v_tablenames Varchar2(
1000);         --多个表名称
v_wherecondition Varchar2(
3000);     --where条件子句
v_posfrom Number;               
--from的位置
v_posselect Number;             
--select的位置
v_poswhere Number;              
--where条件的位置
v_posorderby Number;            
--order by的位置
v_primaryTable Varchar2(
1000);   --表示记录中的主记录的表
v_tmpwhereint Number;                
--临时保存where的位置
v_tmpfromint Number;                 
--临时保存from的位置
v_tmpint Number;
v_tmpstr Varchar2(
8000);
v_flag Number;
v_tablecountsflag Number;

Begin
v_flag :
= 0--默认状态
v_tablecountsflag :
=0;
------------------------------------------------------------先处理相关变量
v_posfrom :
= instr(lower(p_SqlSelect), 'from '1,1); --查找第一个from的位置
v_selectfields :
= substr(p_SqlSelect,1,v_posfrom-1); --取出第一个from之前的select ######
--判断语句是否还有select子句
v_tmpfromint :
= instr(lower(v_selectfields),'from ',v_posfrom+5,1); --查找出第二个from的位置
If  v_tmpfromint 
> 0 Then
--如果第二个from存在,需要判断是否第一个select和第一个from之间是否有select
  v_posselect :
= instr(lower(substr(p_SqlSelect,1,v_posfrom)),'select ',1,2);
  If v_posselect 
> 0 Then
  
--说明在查询的字段中有 select from 子语句,情况较复杂
  
--格式:S--(S--F)----F--.
    v_flag :
= 1;
     Goto do_flag;
  Else
  
--说明第二个from是 视图或者where条件中的从句,第一个from就是最外层的 from
  
--格式:S--F--(..F..)--
  
--v_selectfields := substr(p_SqlSelect,1,v_posfrom-1); --取出第一个from之前的select ######
  
--判断两个from之间是否还有where条件
  v_poswhere :
= instr(lower(p_SqlSelect), 'where ', v_posfrom+5,1); --查找两个from之间的where,这也是第一个where
    If v_poswhere 
< v_tmpfromint And v_poswhere > v_posfrom Then
      
--两个from之间有where ,说明第二个from是where条件中的 select from子句
      
--格式:S--F--W--(..F..)--
      v_wherecondition :
= substr(p_SqlSelect,v_poswhere);
      v_tablenames :
= substr(p_SqlSelect,v_posfrom+5,v_poswhere-(v_posfrom+5));
      Goto do_flag;
    Elsif v_poswhere 
> v_tmpfromint Then
      
--where的位置大于第二个from ,说明 from的视图或表是一个子查询
      
--格式:S--F--(S--F--W)
      
--这里需要判断在第一个where之后是否还有where,
      v_tmpwhereint :
= instr(lower(p_SqlSelect), 'where ', v_poswhere+6,1); --取出全局中第二个where的位置
      If v_tmpwhereint 
> 0 Then
      
--现在的格式:S--F--S--F--W--..W..-- 情况交复杂
        v_flag :
= 1;
         Goto do_flag;
      Else
        
--全局中仅有一个where,这里需要判断where是全局查询条件 还是 from的视图查询条件
        
--通过判断第二个from和第一个where之间是否有‘)’符号
        v_tmpstr :
= substr(p_SqlSelect,v_tmpfromint+5,v_poswhere-(v_tmpfromint+5));
        If  instr(v_tmpstr,
')',-1,1> 0 Then
          
--说明where是全局查询条件
          Goto do_sfw1;
        Else
         
--说明where是from视图的查询条件
         Goto do_orderby;
        End If;
      End If;
    Else 
--没有查询到where条件的位置,说明一个where条件都没有
      Goto do_orderby;
    End If;
  End If;
End If;
 
-------如果没有select from子句,全局找不到第二个 from -----------------------------------
<<do_sfw1>>
v_selectfields :
= substr(p_SqlSelect,1,v_posfrom-1); --取出第一个from之前的select ######
--如果没有select from子句,查找where的位置
v_poswhere :
= instr(lower(p_SqlSelect), 'where ', v_posfrom+4,1); --查找第一个where的位置
--判断语句中第一个where是否存在
If v_poswhere 
> 0 Then --存在
   v_wherecondition :
= substr(p_SqlSelect,v_poswhere);
   v_tablenames :
= substr(p_SqlSelect,v_posfrom+5,v_poswhere-(v_posfrom+5));
   Goto do_flag;
End If;

<<do_orderby>>
--如果语句中没有where条件,先查询是否有order by 排序条件 从字符串最后一个字符查找
v_posorderby :
= instr(lower(p_SqlSelect), 'order by '-1,1); --查找order by的位置
If v_posorderby 
>0 Then
--如果语句中有order by
 v_wherecondition :
= substr(p_SqlSelect,v_posorderby);
 v_tablenames :
= substr(p_SqlSelect,v_posfrom+5,v_posorderby-(v_posfrom+5));
Else
--如果语句中也没有order by
  v_wherecondition :
= '';
  v_tablenames :
= substr(p_SqlSelect,v_posfrom+5);
End If;
<<do_flag>>
If v_flag 
<= 0 Then
   
--这里要处理获得primarytable主视图表的名称
  
<<do_primarytable>>
  v_tablenames :
= trim(v_tablenames);
  v_tmpint :
= instr(v_tablenames,',',1,1);
  If v_tmpint 
> 0 Then --判断是否是多个表的联合查询
     v_primaryTable :
= substr(v_tablenames,1,v_tmpint-1);
     v_tablecountsflag :
= 1--标识符说明有多个表
  Else
      v_tmpint :
= instr(lower(v_tablenames),'join',1,1);
      If v_tmpint 
> 0 Then
         v_primaryTable :
= substr(v_tablenames,1,v_tmpint-1);
         v_primaryTable :
= Replace(v_primaryTable,'out','');
         v_primaryTable :
= Replace(v_primaryTable,'left','');
         v_primaryTable :
= Replace(v_primaryTable,'right','');
         v_primaryTable :
= Replace(v_primaryTable,'inner','');
      Else
         v_primaryTable :
= v_tablenames;
      End If;
  End If;
  v_primaryTable :
= lower(trim(v_primaryTable));
  v_primaryTable :
= replace(replace(v_primaryTable,chr(13)),chr(10));    --去除换行符
  
--去除多个空格的情况
  v_primaryTable :
= Replace(v_primaryTable,'   ',' '); --去除3个连续空格
  v_primaryTable :
= Replace(v_primaryTable,'  ',' '); --去除2个连续空格
  v_tmpint :
= instr(v_primaryTable,' ',1,1);
  If v_tmpint 
> 0 Then
     v_primaryTable :
= trim(substr(v_primaryTable,v_tmpint+1));
  Else 
--当没有设置表的别名, 自己给定别名
     v_tmpstr :
= v_primaryTable || ' xxjmytb';
     v_tablenames :
= Replace(lower(v_tablenames),v_primaryTable,v_tmpstr);
     
--先将WHERE和SELECT变量中的'转义
     --v_wherecondition := Replace(v_wherecondition,chr(39),'''');
     
--v_selectfields := Replace(v_selectfields,chr(39),'''');
      
--还要替换掉where条件中的表名称的
      v_wherecondition :
= lower(v_wherecondition);
      v_wherecondition :
= Replace(v_wherecondition,v_primaryTable||'.','xxjmytb.');
      
--还有替换掉selectfields中的表名称
      v_selectfields :
=lower(v_selectfields);
      v_selectfields :
= Replace(v_selectfields,v_primaryTable||'.','xxjmytb.');
      v_tmpint :
= instr(v_primarytable,'.',-1,1); --查找带点的表名
      If  v_tmpint 
> 0 Then
        v_tmpstr :
= trim(substr(v_primarytable,v_tmpint+1));
        v_tmpstr :
= v_tmpstr||'.';
        v_wherecondition :
= Replace(v_wherecondition,v_tmpstr,'xxjmytb.');
        v_selectfields :
= Replace(v_selectfields,v_tmpstr,'xxjmytb.'); --替换掉selectfields中的表名称
      End If;
     v_primarytable :
= 'xxjmytb';
  End If;
  v_tablenames :
= ' ' || v_tablenames || ' ';
  
---取分页总数-----------------------目的是为了在统计的时候将字段中的相关方法出去
  v_sql :
= 'select count(*) from ' || v_tablenames ||  v_wherecondition;
  Execute Immediate v_sql Into v_count; p_OutRecordCount :
= v_count; --将总记录数赋值给返回的参数
  p_OutPageCount :
= ceil(v_count/p_PageSize); --将总页数赋值给返回的参数
  v_heiRownum :
= p_PageIndex * p_PageSize; v_lowRownum := v_heiRownum - p_PageSize + 1--计算开始和起始位置
  v_sql :
= 'select '|| v_primaryTable ||'.rowid as xxjid,rownum as rownn_xxj from ' || v_tablenames || v_wherecondition;
  v_sql :
= 'select xxjid,rownum as rownn_xxj from (' || v_sql || ') where rownn_xxj <=' || to_char(v_heiRownum);
  v_sql :
= 'select xxjid from ('|| v_sql ||') where rownn_xxj >= ' || to_char(v_lowRownum);
  If v_tablecountsflag 
> 0 Then
     v_sql :
= v_selectfields || ',rownum as rownn_xxj from ' || v_tablenames || ',('|| v_sql ||') xxjlast where xxjlast.xxjid='|| v_primaryTable || '.rowid and '|| substr(trim(v_wherecondition),6);
  Else
      v_sql :
= v_selectfields || ',rownum as rownn_xxj from ' || v_tablenames || ',('|| v_sql ||') xxjlast where xxjlast.xxjid='|| v_primaryTable || '.rowid';
  End If;
Else
  v_sql :
= 'select count(*) from (' || p_SqlSelect || ')';
  execute immediate v_sql into v_count;
  p_OutRecordCount :
= v_count;
  p_OutPageCount :
= ceil(v_count/p_PageSize); --将总页数赋值给返回的参数
  v_heiRownum :
= p_PageIndex * p_PageSize; v_lowRownum := v_heiRownum - p_PageSize + 1;
  v_sql :
= 'SELECT * FROM (SELECT A.*, rownum rownn_xxj FROM  ('|| p_SqlSelect ||') A WHERE rownum <= '|| to_char(v_heiRownum) || ' ) B WHERE rownn_xxj >= ' || to_char(v_lowRownum) ;
End If;
--#############如果是具体某条记录的详细信息################################################
If p_RecordIndex 
> 0 Then
   v_sql :
= 'select * from ('|| v_sql ||') where rownn_xxj='||to_char(p_RecordIndex);
End If;
--#########################################################################################
Open p_OutCursor For v_sql;
End GetRecords;
---------------------------------------------------------------------------------------------------------------------------

End PKG_PageSplit;
/
posted @ 2007-07-30 10:22  李占卫  阅读(383)  评论(0编辑  收藏  举报