• 分页存储过程



    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;
    /
  • 相关阅读:
    注解的作用
    962. Maximum Width Ramp
    594. Longest Harmonious Subsequence
    1042. Flower Planting With No Adjacent
    419. Battleships in a Board
    1041. Robot Bounded In Circle
    leetcode 395. Longest Substring with At Least K Repeating Characters(高质量题)
    leetcode 44. Wildcard Matching(模糊匹配)
    HEU预热赛
    780. Reaching Points
  • 原文地址:https://www.cnblogs.com/tommyli/p/836046.html
Copyright © 2020-2023  润新知